summaryrefslogtreecommitdiff
path: root/src/ptime.ml
diff options
context:
space:
mode:
Diffstat (limited to 'src/ptime.ml')
-rw-r--r--src/ptime.ml70
1 files changed, 51 insertions, 19 deletions
diff --git a/src/ptime.ml b/src/ptime.ml
index e3ef8f2..00ff119 100644
--- a/src/ptime.ml
+++ b/src/ptime.ml
@@ -28,6 +28,15 @@ let jd_to_date jd =
let year = 100 * b + d - 4800 + (m / 10) in
(year, month, day)
+let jd_to_year jd = (* Same as above but only for the year *)
+ let a = jd + 32044 in
+ let b = (4 * a + 3) / 146097 in
+ let c = a - ((146097 * b) / 4) in
+ let d = (4 * c + 3) / 1461 in
+ let e = c - ((1461 * d) / 4) in
+ let m = (5 * e + 2) / 153 in
+ 100 * b + d - 4800 + (m / 10)
+
let jd_of_date (year, month, day) =
let a = (14 - month) / 12 in
let y = year + 4800 - a in
@@ -441,21 +450,26 @@ let to_date_time ?(tz_offset_s = 0) t =
let ss = Int64.(to_int (div mm_rem ps_count_in_s)) in
date, ((hh, mm, ss), tz_offset_s)
-let of_date date = of_date_time (date, ((00, 00, 00), 0))
-let to_date t = fst (to_date_time ~tz_offset_s:0 t)
+let of_date ?tz_offset_s:(tz = 0) date = of_date_time (date, ((00, 00, 00), tz))
+let to_date ?tz_offset_s t = fst (to_date_time ?tz_offset_s t)
+let of_year ?tz_offset_s y = of_date ?tz_offset_s (y, 01, 01)
+let to_year ?(tz_offset_s = 0) t =
+ let d = match add_span t (Span.of_int_s tz_offset_s) with
+ | None -> fst t (* fallback to UTC *) | Some (local_d, _) -> local_d
+ in
+ jd_to_year (d + jd_posix_epoch)
+
+let weekday_num ?(tz_offset_s = 0) t =
+ let (d, _) = Span.add t (Span.of_int_s tz_offset_s) in
+ (* N.B. in contrast to [to_date_time] we don't care if we fall outside
+ [min;max]. Even if it happens the result of the computation is still
+ correct *)
+ let i = (d + 4 (* Epoch, d = 0, was a thu, we want 4 for that day *)) mod 7 in
+ if i < 0 then 7 + i else i
let weekday =
- let wday =
- (* Epoch was a thursday *)
- [| `Thu; `Fri; `Sat; `Sun; `Mon; `Tue; `Wed |]
- in
- fun ?(tz_offset_s = 0) t ->
- let (d, _) = Span.add t (Span.of_int_s tz_offset_s) in
- (* N.B. in contrast to [to_date_time] we don't care if we fall outside
- [min;max]. Even if it happens the result of the computation is still
- correct *)
- let i = d mod 7 in
- wday.(if i < 0 then 7 + i else i)
+ let wday = [| `Sun; `Mon; `Tue; `Wed; `Thu; `Fri; `Sat; |] in
+ fun ?tz_offset_s t -> wday.(weekday_num ?tz_offset_s t)
(* RFC 3339 timestamp conversions *)
@@ -476,10 +490,18 @@ let pp_rfc3339_error ppf = function
in
Format.fprintf ppf "@[expected@ a@ character@ in:%a@]" pp_chars cs
+let pp_range ppf (s, e) =
+ if s = e then Format.pp_print_int ppf s else Format.fprintf ppf "%d-%d" s e
+
+let _rfc3339_error_to_string (r, err) =
+ Format.asprintf "@[<h>%a: %a@]" pp_range r pp_rfc3339_error err
+
+let rfc3339_string_error = function
+| Ok _ as v -> v | Error (`RFC3339 e) -> Error (_rfc3339_error_to_string e)
+
let rfc3339_error_to_msg = function
-| Ok _ as v -> v
-| Error (`RFC3339 ((s, e), err)) ->
- Error (`Msg (Format.asprintf "%d-%d: %a" s e pp_rfc3339_error err))
+| Ok _ as v -> v | Error (`RFC3339 e) ->
+ Error (`Msg (_rfc3339_error_to_string e))
exception RFC3339 of (int * int) * rfc3339_error (* Internal *)
@@ -541,10 +563,20 @@ let parse_frac_ps pos max s =
let parse_tz_s ~strict pos max s =
let parse_tz_mag sign pos =
let hh_pos = pos in
- let mm_pos = hh_pos + 3 in
let hh = parse_digits ~count:2 hh_pos max s in
- parse_char ':' (mm_pos - 1) max s;
- let mm = parse_digits ~count:2 mm_pos max s in
+ let mm, mm_pos = match strict with
+ | true ->
+ let mm_pos = hh_pos + 3 in
+ parse_char ':' (mm_pos - 1) max s;
+ parse_digits ~count:2 mm_pos max s, mm_pos
+ | false ->
+ let next = hh_pos + 2 in
+ if next > max || not (s.[next] = ':' || is_digit s.[next])
+ then (0, hh_pos (* end pos of parse - 1, one is added at the end *))
+ else
+ let mm_pos = if s.[next] = ':' then hh_pos + 3 else hh_pos + 2 in
+ parse_digits ~count:2 mm_pos max s, mm_pos
+ in
if hh > 23 then error (hh_pos, hh_pos + 1) `Invalid_stamp else
if mm > 59 then error (mm_pos, mm_pos + 1) `Invalid_stamp else
let secs = hh * 3600 + mm * 60 in