package lunar

  1. Overview
  2. Docs
A very small date management library

Install

dune-project
 Dependency

Authors

Maintainers

Sources

lunar-1.1.0.tbz
sha256=f158deac67b864f3edd7d1242b3340a0f218d4465b9e4108501a02197594d0f9
sha512=acf9a3ea508c3df2351aec6ea8299583be128f02d2d891ab82a2999ad6ba00c967962ede7d96782c27a7edcb7f78db08380293a8bf044a567a749872bbc417a8

doc/src/lunar/duration.ml.html

Source file duration.ml

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
(* Copyright (c) 2026, Cargocut and the Lunar developers.
   All rights reserved.

   SPDX-License-Identifier: BSD-3-Clause *)

type t = int64

let zero = Int64.zero
let one = Int64.one
let from_int64 x = x
let from_seconds = Int64.of_int
let from_minutes x = x |> from_seconds |> Int64.mul 60L
let from_hours x = x |> from_seconds |> Int64.mul 3600L
let from_days x = x |> from_seconds |> Int64.mul 86400L
let one_day = from_days 1
let one_minute = from_minutes 1
let one_hour = from_hours 1
let abs = Int64.abs
let neg x = Int64.(sub zero x)

let div_floor a b =
  let q = a / b
  and r = a mod b in
  if (not (Int.equal 0 r)) && not (Bool.equal (r > 0) (b > 0))
  then pred q
  else q
;;

let gregorian_cycle = 146097
let epoch_shift = 719468

let days_from_civil year month day =
  (* NOTE: This the Howard Hinnant’s "civil calendar" algorithms.
     See: https://howardhinnant.github.io/date/date.html *)
  let year = if month <= 2 then pred year else year in
  let era = div_floor year 400 in
  let y = year - (era * 400) in
  let m = if month > 2 then month - 3 else month + 9 in
  let d = (y * 365) + (y / 4) - (y / 100) + ((((153 * m) + 2) / 5) + day - 1) in
  (era * gregorian_cycle) + d - epoch_shift
;;

let civil_from_days d =
  (* NOTE: This the Howard Hinnant’s dual "civil calendar" algorithms.
     See: https://howardhinnant.github.io/date/date.html *)
  let shift = d + epoch_shift in
  let era = div_floor shift gregorian_cycle in
  let day_of_era = shift - (era * gregorian_cycle) in
  let year_of_era =
    (day_of_era
     - (day_of_era / 1460)
     + (day_of_era / 36524)
     - (day_of_era / 146096))
    / 365
  in
  let year = year_of_era + (era * 400) in
  let day_of_year =
    day_of_era - ((365 * year_of_era) + (year_of_era / 4) - (year_of_era / 100))
  in
  let m = ((5 * day_of_year) + 2) / 153 in
  let day = day_of_year - (((153 * m) + 2) / 5) + 1 in
  let month = if m < 10 then m + 3 else m - 9 in
  let year = if month <= 2 then year + 1 else year in
  year, month, day
;;

let from_datetime ~year ~month ~day ~hour ~min ~sec =
  let days = days_from_civil year month day |> from_days in
  days
  |> Int64.add (from_hours hour)
  |> Int64.add (from_minutes min)
  |> Int64.add (from_seconds sec)
;;

let to_datetime duration =
  let days = one_day |> Int64.div duration |> Int64.to_int in
  let rem_secs = one_day |> Int64.rem duration |> Int64.to_int in
  let days, rem_secs =
    if rem_secs < 0
    then days - 1, rem_secs + Int64.to_int one_day
    else days, rem_secs
  in
  let year, month, day = civil_from_days days in
  let hour = rem_secs / 3600
  and min = rem_secs mod 3600 / 60
  and sec = rem_secs mod 60 in
  year, month, day, hour, min, sec
;;

let to_int64 x = x
let compare = Int64.compare
let equal = Int64.equal
let add = Int64.add
let sub = Int64.sub
let mul ts x = Int64.(mul ts (of_int x))
let succ = Int64.succ
let pred = Int64.pred

let wdhms x =
  let weeks, rem = Util.i64_div_mod_floor x (from_days 7) in
  let days, rem = Util.i64_div_mod_floor rem one_day in
  let hour, rem = Util.i64_div_mod_floor rem one_hour in
  let min, sec = Util.i64_div_mod_floor rem one_minute in
  (* MAYBE: an opportunity for labelled-tuple. *)
  ( Int64.to_int weeks
  , Int64.to_int days
  , Int64.to_int hour
  , Int64.to_int min
  , Int64.to_int sec )
;;

let dhms x =
  let days, rem = Util.i64_div_mod_floor x one_day in
  let hour, rem = Util.i64_div_mod_floor rem one_hour in
  let min, sec = Util.i64_div_mod_floor rem one_minute in
  (* MAYBE: an opportunity for labelled-tuple. *)
  Int64.to_int days, Int64.to_int hour, Int64.to_int min, Int64.to_int sec
;;

let hms x =
  let hours, rem = Util.i64_div_mod_floor x one_hour in
  let min, sec = Util.i64_div_mod_floor rem one_minute in
  (* MAYBE: an opportunity for labelled-tuple. *)
  Int64.to_int hours, Int64.to_int min, Int64.to_int sec
;;

let weekday x =
  let weekdays = Weekday.[| Sun; Mon; Tue; Wed; Thu; Fri; Sat |] in
  let d, _, _, _ = dhms x in
  let id = (d + 4) mod 7 in
  weekdays.((id + 7) mod 7)
;;

let to_seconds t = t |> to_int64 |> Int64.to_int
let to_minutes t = Int64.(to_int (div t one_minute))
let to_hours t = Int64.(to_int (div t one_hour))
let to_days t = Int64.(to_int (div t one_day))

module CE = struct
  type nonrec t = t

  let equal = equal
  let compare = compare
end

module Infix = struct
  let ( + ) = Int64.add
  let ( - ) = Int64.sub
  let ( * ) = mul

  include Util.Make_equal_infix (CE)
  include Util.Make_compare_infix (CE)
end

include Util.Make_compare_helpers (CE)
include Infix