4 people like it.

System.TimeSpan user-friendly formatting

Formatting a Timespan to something fully descriptive and user friendly.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
open System

type Part = Days of int
          | Hours of int
          | Minutes of int
          | Seconds of int
          | Milliseconds of int
let bigPartString p = 
  match p with
  | Days 0 -> ""
  | Days 1 -> "a day"
  | Days d -> sprintf "%i days" d
  | Hours 0 -> ""
  | Hours 1 -> "an hour"
  | Hours h -> sprintf "%i hours" h
  | Minutes 0 -> ""
  | Minutes 1 -> "a minute"
  | Minutes m -> sprintf "%i minutes" m
  | _ -> ""
let smallPartString s m =
  match s, m with
  | Seconds 0, Milliseconds 0  -> ""
  | Seconds 0, Milliseconds ms -> sprintf "%ims" ms
  | Seconds 1, Milliseconds 0  -> sprintf "a second"
  | Seconds s, Milliseconds 0  -> sprintf "%i seconds" s
  | Seconds s, Milliseconds ms -> sprintf "%i.%i seconds" s ms
  | _                          -> ""

let formatTimeSpan (ts:TimeSpan) maxParts =
  let makePart (p, v) = (p v, v)
  let bigParts = 
    [ (Days, ts.Days)
      (Hours, ts.Hours)
      (Minutes, ts.Minutes)
    ]
    |> Seq.map makePart
    |> Seq.skipWhile (snd >> ((>) 0))
  
  let flip f a b = f b a

  bigParts 
  |> Seq.map fst
  |> Seq.map bigPartString 
  |> flip Seq.append [smallPartString (Seconds ts.Seconds) (Milliseconds ts.Milliseconds)]
  |> Seq.filter (not << String.IsNullOrEmpty)
  |> Seq.truncate maxParts
  |> fun parts -> String.Join(", ", parts)

let ts1 = TimeSpan.FromMinutes(20000.50354)
let ts2 = TimeSpan.FromMinutes(1.5)
let ts3 = TimeSpan.FromSeconds(10.522525)
let ts4 = TimeSpan.FromSeconds(0.0052)

for t in [ts1; ts2; ts3; ts4] do
  printfn "----------"
  for m in [-1..7] do  
    printfn "%s" (formatTimeSpan t m)
namespace System
type Part =
  | Days of int
  | Hours of int
  | Minutes of int
  | Seconds of int
  | Milliseconds of int

Full name: Script.Part
union case Part.Days: int -> Part
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
union case Part.Hours: int -> Part
union case Part.Minutes: int -> Part
union case Part.Seconds: int -> Part
union case Part.Milliseconds: int -> Part
val bigPartString : p:Part -> string

Full name: Script.bigPartString
val p : Part
val d : int
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val h : int
val m : int
val smallPartString : s:Part -> m:Part -> string

Full name: Script.smallPartString
val s : Part
val m : Part
val ms : int
val s : int
val formatTimeSpan : ts:TimeSpan -> maxParts:int -> string

Full name: Script.formatTimeSpan
val ts : TimeSpan
Multiple items
type TimeSpan =
  struct
    new : ticks:int64 -> TimeSpan + 3 overloads
    member Add : ts:TimeSpan -> TimeSpan
    member CompareTo : value:obj -> int + 1 overload
    member Days : int
    member Duration : unit -> TimeSpan
    member Equals : value:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member Hours : int
    member Milliseconds : int
    member Minutes : int
    ...
  end

Full name: System.TimeSpan

--------------------
TimeSpan()
TimeSpan(ticks: int64) : unit
TimeSpan(hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : unit
val maxParts : int
val makePart : (('a -> 'b) * 'a -> 'b * 'a)
val p : ('a -> 'b)
val v : 'a
val bigParts : seq<Part * int>
property TimeSpan.Days: int
property TimeSpan.Hours: int
property TimeSpan.Minutes: int
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val skipWhile : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.skipWhile
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
val flip : (('a -> 'b -> 'c) -> 'b -> 'a -> 'c)
val f : ('a -> 'b -> 'c)
val a : 'b
val b : 'a
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
val append : source1:seq<'T> -> source2:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.append
property TimeSpan.Seconds: int
property TimeSpan.Milliseconds: int
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
Multiple items
type String =
  new : value:char -> string + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

Full name: System.String

--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
String.IsNullOrEmpty(value: string) : bool
val truncate : count:int -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.truncate
val parts : seq<string>
String.Join(separator: string, values: Collections.Generic.IEnumerable<string>) : string
String.Join<'T>(separator: string, values: Collections.Generic.IEnumerable<'T>) : string
String.Join(separator: string, [<ParamArray>] values: obj []) : string
String.Join(separator: string, [<ParamArray>] value: string []) : string
String.Join(separator: string, value: string [], startIndex: int, count: int) : string
val ts1 : TimeSpan

Full name: Script.ts1
TimeSpan.FromMinutes(value: float) : TimeSpan
val ts2 : TimeSpan

Full name: Script.ts2
val ts3 : TimeSpan

Full name: Script.ts3
TimeSpan.FromSeconds(value: float) : TimeSpan
val ts4 : TimeSpan

Full name: Script.ts4
val t : TimeSpan
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Raw view Test code New version

More information

Link:http://fssnip.net/q0
Posted:9 years ago
Author:Gauthier Segay
Tags: timespan , formatting