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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
type t = {
s : int;
ns : int;
}
type error =
[ `Invalid_hour of int
| `Invalid_minute of int
| `Invalid_second of int
| `Invalid_s_frac of float
| `Invalid_ns of int
]
exception Error_exn of error
let make ?(ns = 0) ?(s_frac = 0.0) ~hour ~minute ~second () : (t, error) result
=
if hour < 0 || 24 < hour then Error (`Invalid_hour hour)
else if minute < 0 || 59 < minute then Error (`Invalid_minute minute)
else if second < 0 || 60 < second then Error (`Invalid_second second)
else if s_frac < 0. then Error (`Invalid_s_frac s_frac)
else if ns < 0 then Error (`Invalid_ns ns)
else
let ns = ns + int_of_float (s_frac *. Span.ns_count_in_s_float) in
if ns >= Span.ns_count_in_s then Error (`Invalid_ns ns)
else
match
if hour = 24 then
if minute = 0 && second = 0 && ns = 0 then
Ok (23, 59, 59, Span.ns_count_in_s - 1)
else Error (`Invalid_hour hour)
else Ok (hour, minute, second, ns)
with
| Error e -> Error e
| Ok (hour, minute, second, ns) ->
let is_leap_second = second = 60 in
let second = if is_leap_second then 59 else second in
let ns = if is_leap_second then ns + Span.ns_count_in_s else ns in
let s =
CCInt64.to_int
@@ Span.get_s
@@ Span.For_human'.make_exn ~sign:`Pos ~hours:hour ~minutes:minute
~seconds:second ()
in
Ok { s; ns }
let make_exn ?ns ?s_frac ~hour ~minute ~second () : t =
match make ~hour ~minute ~second ?ns ?s_frac () with
| Error e -> raise (Error_exn e)
| Ok x -> x
let to_span (x : t) : Span.t =
Span.make_small ~s:x.s ~ns:(x.ns mod Span.ns_count_in_s) ()
let of_span (x : Span.t) : t option =
if Span.(zero <= x && x < Constants.one_day) then
let s = CCInt64.to_int @@ Span.get_s x in
let ns = Span.get_ns_offset x in
Some { s; ns }
else None
let is_leap_second (x : t) = x.ns >= Span.ns_count_in_s
let equal (x : t) (y : t) = x.s = y.s && x.ns = y.ns
type view = {
hour : int;
minute : int;
second : int;
ns : int;
}
let view (x : t) : view =
let v = Span.For_human'.view @@ to_span x in
{ hour = v.hours; minute = v.minutes; second = v.seconds; ns = v.ns }
let hour x = (view x).hour
let minute x = (view x).minute
let second x = (view x).second
let ns x = (view x).ns