package lunar
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
A very small date management library
Install
dune-project
Dependency
Authors
Maintainers
Sources
lunar-1.3.0.tbz
sha256=cc0dc0ca027423d1892392872f7be35ff2c1acc5579ddf895b60cd6c77534e4a
sha512=5a252698e6bf0eb23f41d61c5b56deee03c8e7ccc7dca11145388e9cf1a12e5046c3cb09ee3472fe67dca700387aa108616c9eb128e154faec0f6d11eaaf010a
doc/src/lunar/datetime.ml.html
Source file datetime.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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357(* Copyright (c) 2026, Cargocut and the Lunar developers. All rights reserved. SPDX-License-Identifier: BSD-3-Clause *) type t = Date.t * Time.t type error = | Invalid_date of Date.error | Invalid_time of Time.error | Invalid of Date.error * Time.error | Invalid_string of string exception Invalid_datetime of error let from date time = date, time let from_date date = from date Time.midnight let epoch = from_date Date.epoch let make_aux f ?at ~year ~month ~day () = let hour, min, sec = Option.value ~default:(0, 0, 0) at in match f ~year ~month ~day (), Time.make ~hour ~min ~sec () with | Ok date, Ok time -> Ok (from date time) | Error a, Error b -> Error (Invalid (a, b)) | Error a, _ -> Error (Invalid_date a) | _, Error a -> Error (Invalid_time a) ;; let make = make_aux Date.make let make' = make_aux Date.make' let make_exn ?at ~year ~month ~day () = match make ?at ~year ~month ~day () with | Error err -> raise (Invalid_datetime err) | Ok x -> x ;; let make_exn' ?at ~year ~month ~day () = match make' ?at ~year ~month ~day () with | Error err -> raise (Invalid_datetime err) | Ok x -> x ;; let from_string s = (* TODO: improve cases. *) match s |> Util.split_on_chars (function | 'T' | ' ' | 't' | '\n' | '\t' -> true | _ -> false) |> List.filter_map (fun x -> match String.trim x with | "" -> None | x -> Some x) with | [ date; time ] -> (match Date.from_string date, Time.from_string time with | Ok date, Ok time -> Ok (from date time) | Error a, Error b -> Error (Invalid (a, b)) | Error a, _ -> Error (Invalid_date a) | _, Error b -> Error (Invalid_time b)) | [ date ] -> Date.from_string date |> Result.map_error (fun err -> Invalid_date err) |> Result.map from_date | _ -> Error (Invalid_string s) ;; let from_string_exn s = match from_string s with | Ok x -> x | Error err -> raise (Invalid_datetime err) ;; let from_duration d = let year, month, day, hour, min, sec = Duration.to_datetime d in let at = hour, min, sec in let month = (* NOTE: Result.get_ok should be safe because of [to_datetime]. *) month |> Month.from_int |> Result.get_ok in make_exn ~at ~year ~month ~day () ;; let to_duration (d, t) = Duration.(Date.to_duration d + Time.to_duration t) let diff a b = let a = to_duration a and b = to_duration b in Duration.sub a b ;; let to_pair x = x let date = fst let time = snd let on_date f x = x |> date |> f let on_time f x = x |> time |> f let map_date f (d, t) = f d, t let map_time f (d, t) = d, f t let with_time t dt = map_time (fun _ -> t) dt let with_date d dt = map_date (fun _ -> d) dt let hour = on_time Time.hour let minute = on_time Time.minute let second = on_time Time.second let era = on_date Date.era let year_of_era = on_date Date.year_of_era let century_of_era = on_date Date.century_of_era let year_of_century = on_date Date.year_of_century let year = on_date Date.year let quarter = on_date Date.quarter let month = on_date Date.month let day_of_month = on_date Date.day_of_month let day_of_week = on_date Date.day_of_week let days_in_month = on_date Date.days_in_month let day_of_year = on_date Date.day_of_year let week_of_year = on_date Date.week_of_year let day = on_date Date.day let weekday = on_date Date.weekday let to_string dt = let d = date dt and t = time dt in Date.to_string d ^ "T" ^ Time.to_string t ;; let equal a b = let da = date a and db = date b in let c = Date.equal da db in if c then ( let ta = time a and tb = time b in Time.equal ta tb) else c ;; let compare a b = let da = date a and db = date b in let c = Date.compare da db in if Int.equal c 0 then ( let ta = time a and tb = time b in Time.compare ta tb) else c ;; let as_duration f dt = f (to_duration dt) |> from_duration let add d dt = as_duration (fun dt -> Duration.add dt d) dt let sub d dt = as_duration (fun dt -> Duration.sub dt d) dt module CE = struct type nonrec t = t let equal = equal let compare = compare end module Infix = struct let ( + ) x y = add y x let ( - ) x y = sub y x include Util.Make_equal_infix (CE) include Util.Make_compare_infix (CE) end include Util.Make_compare_helpers (CE) let add_seconds n = add (Duration.from_seconds n) let sub_seconds n = sub (Duration.from_seconds n) let add_minutes n = add (Duration.from_minutes n) let sub_minutes n = sub (Duration.from_minutes n) let add_hours n = add (Duration.from_hours n) let sub_hours n = sub (Duration.from_hours n) let add_days i = map_date (Date.add_days i) let sub_days i = map_date (Date.sub_days i) let add_weeks i = map_date (Date.add_weeks i) let sub_weeks i = map_date (Date.sub_weeks i) let add_months i = map_date (Date.add_months i) let sub_months i = map_date (Date.sub_months i) let add_quarters i = map_date (Date.add_quarters i) let sub_quarters i = map_date (Date.sub_quarters i) let add_years i = map_date (Date.add_years i) let sub_years i = map_date (Date.sub_years i) let truncate resolution dt = match resolution with | `duration dur -> map_time (Time.truncate (`duration dur)) dt | #Resolution.for_date as r -> dt |> map_date (Date.truncate r) |> with_time Time.midnight ;; let floor = truncate let ceil resolution dt = (* KLUDGE: We need to keep logic since date and time ar now connected. *) match resolution with | `duration dur -> let tt = time dt in let tr = Time.truncate (`duration dur) tt in if Time.equal tt tr then dt else add dur (with_time tr dt) | #Resolution.for_date as r -> let t = truncate r dt in if equal dt t then dt else ( match r with | `day -> add_days 1 t | `week _ -> add_weeks 1 t | `month -> add_months 1 t | `quarter -> add_quarters 1 t | `year -> add_years 1 t) ;; let round resolution dt = (* KLUDGE: We need to keep logic since date and time ar now connected. *) match resolution with | `duration dur -> map_time (Time.round (`duration dur)) dt | #Resolution.for_date as r -> let t = truncate r dt and c = ceil r dt in if equal t c then t else ( let dt = diff dt t and dc = diff c dt in if Duration.(dt <= dc) then t else c) ;; let start_of_day dt = with_time Time.midnight dt let end_of_day dt = with_time Time.end_of_day dt let to_midnight f dt = dt |> map_date f |> start_of_day let to_end_day f dt = dt |> map_date f |> end_of_day let succ = add_seconds 1 let pred = sub_seconds 1 let succ_second = succ let pred_second = pred let succ_minute dt = dt |> add_minutes 1 |> truncate Resolution.minute let pred_minute dt = dt |> sub_minutes 1 |> truncate Resolution.minute let succ_hour dt = dt |> add_hours 1 |> truncate Resolution.hour let pred_hour dt = dt |> sub_hours 1 |> truncate Resolution.hour let succ_day ?where dt = to_midnight (Date.succ_day ?where) dt let pred_day ?where dt = to_midnight (Date.pred_day ?where) dt let succ_day_of_week wd dt = to_midnight (Date.succ_day_of_week wd) dt let pred_day_of_week wd dt = to_midnight (Date.pred_day_of_week wd) dt let succ_weekday dt = to_midnight Date.succ_weekday dt let pred_weekday dt = to_midnight Date.pred_weekday dt let succ_week ?week_start dt = to_midnight (Date.succ_week ?week_start) dt let pred_week ?week_start dt = to_midnight (Date.pred_week ?week_start) dt let succ_month dt = to_midnight Date.succ_month dt let pred_month dt = to_midnight Date.pred_month dt let succ_quarter dt = to_midnight Date.succ_quarter dt let pred_quarter dt = to_midnight Date.pred_quarter dt let succ_year dt = to_midnight Date.succ_year dt let pred_year dt = to_midnight Date.pred_year dt let tomorrow dt = succ_day dt let yesterday dt = pred_day dt let start_of_minute dt = map_time Time.start_of_minute dt let start_of_hour dt = map_time Time.start_of_hour dt let end_of_minute dt = map_time Time.end_of_minute dt let end_of_hour dt = map_time Time.end_of_hour dt let start_of_morning dt = with_time Time.start_of_morning dt let end_of_morning dt = with_time Time.end_of_morning dt let start_of_afternoon dt = with_time Time.start_of_afternoon dt let end_of_afternoon dt = with_time Time.end_of_afternoon dt let start_of_evening dt = with_time Time.start_of_evening dt let end_of_evening dt = with_time Time.end_of_evening dt let start_of_night dt = with_time Time.start_of_night dt let end_of_night dt = with_time Time.end_of_night dt let at_noon = start_of_afternoon let start_of_week ?week_start dt = to_midnight (Date.start_of_week ?week_start) dt ;; let end_of_week ?week_start dt = to_end_day (Date.end_of_week ?week_start) dt let start_of_month dt = to_midnight Date.start_of_month dt let end_of_month dt = to_end_day Date.end_of_month dt let start_of_quarter dt = to_midnight Date.start_of_quarter dt let end_of_quarter dt = to_end_day Date.end_of_quarter dt let start_of_year dt = to_midnight Date.start_of_year dt let end_of_year dt = to_end_day Date.end_of_year dt let age ~birthday t = on_date (Date.age ~birthday) t let is_am dt = on_time Time.is_am dt let is_pm dt = on_time Time.is_pm dt let is_noon dt = on_time Time.is_noon dt let is_midnight dt = on_time Time.is_midnight dt let is_morning dt = on_time Time.is_morning dt let is_afternoon dt = on_time Time.is_afternoon dt let is_evening dt = on_time Time.is_evening dt let is_night dt = on_time Time.is_night dt let is_weekend dt = on_date Date.is_weekend dt let is_weekday dt = on_date Date.is_weekday dt let is_leap_year dt = on_date Date.is_leap_year dt let is_day_of_week wd = on_date (Date.is_day_of_week wd) let is_first_day_of_month dt = on_date Date.is_first_day_of_month dt let is_last_day_of_month dt = on_date Date.is_last_day_of_month dt let is_first_day_of_quarter dt = on_date Date.is_first_day_of_quarter dt let is_last_day_of_quarter dt = on_date Date.is_last_day_of_quarter dt let is_first_day_of_year dt = on_date Date.is_first_day_of_year dt let is_last_day_of_year dt = on_date Date.is_last_day_of_year dt let is_first_day_of_week ?week_start dt = on_date (Date.is_first_day_of_week ?week_start) dt ;; let is_last_day_of_week ?week_start dt = on_date (Date.is_last_day_of_week ?week_start) dt ;; module Map = Stdlib.Map.Make (CE) module Set = Stdlib.Set.Make (CE) module Range = struct include Range.Make (CE) let iterator_second = iterator ~pred:pred_second ~succ:succ_second let iterator_minute = iterator ~pred:pred_minute ~succ:succ_minute let iterator_hour = iterator ~pred:pred_hour ~succ:succ_hour let iterator_day = iterator ~pred:pred_day ~succ:succ_day let iterator_day_of_week weekday = iterator ~pred:(pred_day_of_week weekday) ~succ:(succ_day_of_week weekday) ;; let iterator_week ?week_start () = iterator ~pred:(pred_week ?week_start) ~succ:(succ_week ?week_start) ;; let iterator_month = iterator ~pred:pred_month ~succ:succ_month let iterator_quarter = iterator ~pred:pred_quarter ~succ:succ_quarter let iterator_year = iterator ~pred:pred_year ~succ:succ_year let day dt = make ~first:(start_of_day dt) ~last:(end_of_day dt) let morning dt = make ~first:(start_of_morning dt) ~last:(end_of_morning dt) let afternoon dt = make ~first:(start_of_afternoon dt) ~last:(end_of_afternoon dt) ;; let evening dt = make ~first:(start_of_day dt) ~last:(end_of_evening dt) let night dt = make ~first:(start_of_night dt) ~last:(end_of_night dt) let minute dt = make ~first:(start_of_minute dt) ~last:(end_of_minute dt) let hour dt = make ~first:(start_of_hour dt) ~last:(end_of_hour dt) let week ?week_start t = make ~first:(start_of_week ?week_start t) ~last:(end_of_week ?week_start t) ;; let month t = make ~first:(start_of_month t) ~last:(end_of_month t) let quarter t = make ~first:(start_of_quarter t) ~last:(end_of_quarter t) let year t = make ~first:(start_of_year t) ~last:(end_of_year t) end include Infix
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>