### Querying Across DST Boundary with Timere Source: https://github.com/daypack-dev/timere/blob/main/examples/README.md Demonstrates how to query time intervals across DST changes using Timere. This example specifies a time zone and defines date and time patterns, including handling the DST transition in Australia/Sydney. ```ocaml with_tz (Timere.Time_zone.make_exn "Australia/Sydney") ( years [2020] (* in year 2020 *) & (pattern ~months:[`Apr] ~month_day_ranges:[`Range_inc (2, 7)] () ||| pattern ~months:[`Oct] ~month_day_ranges:[`Range_inc (1, 6)] ()) (* or in Oct 1 to 6 *) & hms_interval_exc (* 11pm to 3am *) (make_hms_exn ~hour:23 ~minute:0 ~second:0) (make_hms_exn ~hour:3 ~minute:0 ~second:0) ) ``` ```text [2020 Apr 02 00:00:00 +11:00:00, 2020 Apr 02 03:00:00 +11:00:00) - 3 hours 0 mins 0 secs [2020 Apr 02 23:00:00 +11:00:00, 2020 Apr 03 03:00:00 +11:00:00) - 4 hours 0 mins 0 secs [2020 Apr 03 23:00:00 +11:00:00, 2020 Apr 04 03:00:00 +11:00:00) - 4 hours 0 mins 0 secs [2020 Apr 04 23:00:00 +11:00:00, 2020 Apr 05 03:00:00 +10:00:00) - 5 hours 0 mins 0 secs <- DST ends at Apr 5th 2am [2020 Apr 05 23:00:00 +10:00:00, 2020 Apr 06 03:00:00 +10:00:00) - 4 hours 0 mins 0 secs [2020 Apr 06 23:00:00 +10:00:00, 2020 Apr 07 03:00:00 +10:00:00) - 4 hours 0 mins 0 secs [2020 Apr 07 23:00:00 +10:00:00, 2020 Apr 08 00:00:00 +10:00:00) - 1 hours 0 mins 0 secs [2020 Oct 01 00:00:00 +10:00:00, 2020 Oct 01 03:00:00 +10:00:00) - 3 hours 0 mins 0 secs [2020 Oct 01 23:00:00 +10:00:00, 2020 Oct 02 03:00:00 +10:00:00) - 4 hours 0 mins 0 secs [2020 Oct 02 23:00:00 +10:00:00, 2020 Oct 03 03:00:00 +10:00:00) - 4 hours 0 mins 0 secs [2020 Oct 03 23:00:00 +10:00:00, 2020 Oct 04 03:00:00 +11:00:00) - 3 hours 0 mins 0 secs <- DST starts at Oct 4th 2am [2020 Oct 04 23:00:00 +11:00:00, 2020 Oct 05 03:00:00 +11:00:00) - 4 hours 0 mins 0 secs [2020 Oct 05 23:00:00 +11:00:00, 2020 Oct 06 03:00:00 +11:00:00) - 4 hours 0 mins 0 secs [2020 Oct 06 23:00:00 +11:00:00, 2020 Oct 07 00:00:00 +11:00:00) - 1 hours 0 mins 0 secs ``` -------------------------------- ### Pretty-Printing Interval Sequences with Timedesc.Interval.pp_seq Source: https://context7.com/daypack-dev/timere/llms.txt Shows how to format a sequence of time intervals for display. Each interval is represented as [start, end_exc), meaning it's left-closed and right-open. Requires specifying a time zone for display. ```ocaml let () = let tz = Timedesc.Time_zone.make_exn "Europe/Berlin" in (* Build two intervals manually *) let t1 = Timedesc.of_iso8601_exn "2024-12-24T18:00:00+01:00" in let t2 = Timedesc.of_iso8601_exn "2024-12-24T22:00:00+01:00" in let t3 = Timedesc.of_iso8601_exn "2024-12-25T00:00:00+01:00" in let t4 = Timedesc.of_iso8601_exn "2024-12-25T06:00:00+01:00" in let ts1 = Timedesc.to_timestamp_single t1 in let ts2 = Timedesc.to_timestamp_single t2 in let ts3 = Timedesc.to_timestamp_single t3 in let ts4 = Timedesc.to_timestamp_single t4 in let seq = List.to_seq [(ts1, ts2); (ts3, ts4)] in Fmt.pr "%a@." (Timedesc.Interval.pp_seq ~display_using_tz:tz ~sep:(Fmt.any "\n") ()) seq (* Output: [2024 Dec 24 18:00:00 +01:00:00, 2024 Dec 24 22:00:00 +01:00:00) [2024 Dec 25 00:00:00 +01:00:00, 2024 Dec 25 06:00:00 +01:00:00) *) ``` -------------------------------- ### Find Christmases on Wednesdays with Timere Source: https://github.com/daypack-dev/timere/blob/main/README.md This example demonstrates how to find all Christmases that fall on a Wednesday from the current date using Timere's interval reasoning capabilities. It requires the Timedesc library for current time and date operations. ```ocaml let () = let open Timere in match resolve ( since (Timedesc.now ()) &&& months [12] &&& days [25] &&& weekdays [`Wed] ) with | Error msg -> failwith msg | Ok s -> Fmt.pr "%a@." (Timedesc.Interval.pp_seq ~sep:(Fmt.any "@.") ()) s ``` -------------------------------- ### Unix Timestamp Operations with Timedesc.Timestamp Source: https://context7.com/daypack-dev/timere/llms.txt Demonstrates basic operations on Unix timestamps, including getting the current time, converting to float seconds, adding a duration, and extracting seconds and nanoseconds. Also shows timestamp comparison. ```ocaml let () = let ts = Timedesc.Timestamp.now () in Printf.printf "now float : %.3f\n" (Timedesc.Timestamp.to_float_s ts); let one_hour = Timedesc.Span.For_human.make_exn ~hours:1 () in let ts2 = Timedesc.Timestamp.(ts + one_hour) in Printf.printf "in 1 hour : %s\n" (Timedesc.Timestamp.to_rfc3339 ~frac_s:0 ts2); let (s, ns) = Timedesc.Timestamp.to_s_ns ts in Printf.printf "s=%Ld ns=%d\n" s ns; (* Compare timestamps *) Printf.printf "ts < ts2 : %b\n" Timedesc.Timestamp.(ts < ts2) (* Output: now float : 1700000000.000 in 1 hour : 2023-11-14T23:13:20+00:00 s=1700000000 ns=0 ts < ts2 : true *) ``` -------------------------------- ### Resolving Timere Expressions to Time Intervals Source: https://context7.com/daypack-dev/timere/llms.txt Illustrates the core functionality of Timere: resolving a time-based expression into a sequence of time intervals. This example finds all future Wednesdays in December. ```ocaml let () = let open Timere in (* All future Wednesdays in December (Christmas check) *) let expr = after (Timedesc.now ()) &&& months [12] &&& days [25] &&& weekdays [`Wed] in (match resolve expr with | Error msg -> failwith msg | Ok s -> s |> OSeq.take 3 |> Seq.iter (fun (x, y) -> Printf.printf "%s\n" (Timedesc.Interval.to_string (x, y)))) (* Output (from 2024): [2024 Dec 25 00:00:00 +00:00:00, 2024 Dec 26 00:00:00 +00:00:00) [2030 Dec 25 00:00:00 +00:00:00, 2030 Dec 26 00:00:00 +00:00:00) [2041 Dec 25 00:00:00 +00:00:00, 2041 Dec 26 00:00:00 +00:00:00) *) ``` -------------------------------- ### Get Current Date-Time with Timedesc.now Source: https://context7.com/daypack-dev/timere/llms.txt Retrieves the current wall-clock date-time. Can optionally specify a time zone for the output. Useful for logging or displaying the current time in a specific region. ```ocaml let () = (* Current time in UTC *) let now_utc = Timedesc.now ~tz_of_date_time:Timedesc.Time_zone.utc () in Printf.printf "UTC now : %s\n" (Timedesc.to_rfc3339 now_utc); (* Current time in Tokyo *) let tz_tokyo = Timedesc.Time_zone.make_exn "Asia/Tokyo" in let now_tokyo = Timedesc.now ~tz_of_date_time:tz_tokyo () in Printf.printf "Tokyo : %s\n" (Timedesc.to_rfc3339 now_tokyo) ``` -------------------------------- ### Timedesc.Interval.pp_seq Source: https://context7.com/daypack-dev/timere/llms.txt Formats a sequence of timestamp intervals for display, representing each interval as [start, end_exc). ```APIDOC ## Timedesc.Interval.pp_seq ### Description Pretty-prints a sequence of timestamp intervals. Each interval is represented as `[start, end_exc)`, meaning it is left-closed and right-open. ### Parameters - **`~display_using_tz`**: The time zone to use for displaying timestamps within the intervals. - **`~sep`**: A formatter for the separator between intervals. ### Example ```ocaml let tz = Timedesc.Time_zone.make_exn "Europe/Berlin" let seq = List.to_seq [(ts1, ts2); (ts3, ts4)] Fmt.pr "%a@." (Timedesc.Interval.pp_seq ~display_using_tz:tz ~sep:(Fmt.any "\n") ()) seq ``` ``` -------------------------------- ### Timedesc.Timestamp operations Source: https://context7.com/daypack-dev/timere/llms.txt Provides functions for working with Unix timestamps, including getting the current time, converting to and from float seconds, and performing arithmetic operations. ```APIDOC ## Timedesc.Timestamp ### Description `Timedesc.Timestamp` is an alias for `Span.t` (seconds since Unix epoch). This module provides functions for manipulating and formatting timestamps. ### Functions - **`now ()`**: Returns the current timestamp. - **`to_float_s ts`**: Converts a timestamp to seconds as a float. - **`to_s_ns ts`**: Converts a timestamp to seconds and nanoseconds as a tuple `(s, ns)`. - **`ts1 + ts2`**: Adds two timestamps (or a timestamp and a span). - **`ts1 < ts2`**: Compares two timestamps. - **`to_rfc3339 ~frac_s ts`**: Formats a timestamp to an RFC 3339/ISO 8601 string. `frac_s` specifies the number of fractional seconds to include. ### Example ```ocaml let ts = Timedesc.Timestamp.now () let ts2 = Timedesc.Timestamp.(ts + Timedesc.Span.For_human.make_exn ~hours:1 ()) Printf.printf "%s\n" (Timedesc.Timestamp.to_rfc3339 ~frac_s:0 ts2) ``` ``` -------------------------------- ### Temporal Bounds with Timere.since, Timere.before, Timere.after Source: https://context7.com/daypack-dev/timere/llms.txt Create half-open Timere expressions relative to a given `Timedesc.t` or timestamp. `after` creates future-bound expressions, while `before` creates past-bound expressions. ```ocaml let () = let open Timere in let now = Timedesc.now () in (* All future Fridays *) let future_fridays = after now &&& weekdays [`Fri] in (* All past Saturdays in 2024 *) let past_saturdays = before now &&& years [2024] &&& weekdays [`Sat] in (match resolve future_fridays with | Error msg -> failwith msg | Ok s -> s |> OSeq.take 2 |> Seq.iter (fun iv -> Printf.printf "next friday: %s\n" (Timedesc.Interval.to_string iv))); (match resolve past_saturdays with | Error msg -> failwith msg | Ok s -> Printf.printf "past saturdays in 2024 so far: %d\n" (OSeq.fold (fun acc _ -> acc + 1) 0 s)) ``` -------------------------------- ### ISO Week Patterns with Timere.iso_week_pattern and Timere.iso_weeks Source: https://context7.com/daypack-dev/timere/llms.txt Match intervals based on ISO week year and week number. `iso_week_pattern` allows specifying year and week ranges, while `iso_weeks` provides a shorthand for specific week numbers across years. ```ocaml let () = let open Timere in (* ISO weeks 1–10 of year 2024 *) let expr = iso_week_pattern ~years:[2024] ~week_ranges:[`Range_inc (1, 10)] () in (match resolve expr with | Error msg -> failwith msg | Ok s -> let count = OSeq.fold (fun acc _ -> acc + 1) 0 s in Printf.printf "intervals in ISO weeks 1-10/2024: %d\n" count); (* Shorthand: just week 52 across all years *) let week52_every_year = iso_weeks [52] in (match resolve (years [2023; 2024] &&& week52_every_year) with | Error msg -> failwith msg | Ok s -> s |> OSeq.take 2 |> Seq.iter (fun iv -> Printf.printf "%s\n" (Timedesc.Interval.to_string iv))) ``` -------------------------------- ### Construct and View Human-Friendly Time Spans Source: https://context7.com/daypack-dev/timere/llms.txt Use `make_exn` to create spans from components like hours and minutes, and `view` to decompose them. Fractional hours can be used with `make_frac_exn`. Supports arithmetic and negative spans. ```ocaml let () = (* "2 hours 15 minutes" *) let s1 = Timedesc.Span.For_human.make_exn ~hours:2 ~minutes:15 () Printf.printf "seconds = %Ld\n" (Timedesc.Span.get_s s1) ``` ```ocaml let () = (* "1.5 hours" using fractional constructor *) let s2 = Timedesc.Span.For_human.make_frac_exn ~hours:1.5 () let v = Timedesc.Span.For_human.view s2 Printf.printf "hours=%d minutes=%d\n" v.hours v.minutes ``` ```ocaml let () = (* Arithmetic *) let s3 = Timedesc.Span.(s1 + s2) Printf.printf "total string: %s\n" (Timedesc.Span.For_human.to_string s3) ``` ```ocaml let () = (* Negative span *) let neg = Timedesc.Span.For_human.make_exn ~sign:`Neg ~hours:1 () Printf.printf "neg: %s\n" (Timedesc.Span.to_string neg) ``` -------------------------------- ### Load Timedesc with Full Tzdb Backend in Utop Source: https://github.com/daypack-dev/timere/blob/main/README.md This snippet shows how to load the necessary Timedesc libraries and backends in the utop interactive toplevel. It includes the full tzdb for timezone data and the default unix local timezone detection. ```ocaml #require "timedesc-tzdb.full";; #require "timedesc-tzlocal.unix";; #require "timedesc";; ``` -------------------------------- ### Handling Zone-less Date-Times with Timedesc.Zoneless Source: https://context7.com/daypack-dev/timere/llms.txt Demonstrates parsing and converting ISO 8601 strings that lack time zone information. It shows how to extract date and time components and how to attach a specific time zone to convert to a zoned timestamp. ```ocaml let () = (* Parse a zone-less ISO 8601 string *) (match Timedesc.Zoneless.of_iso8601 "2024-09-01T08:00:00" with | Error msg -> Printf.printf "error: %s\n" msg | Ok zl -> let d = Timedesc.Zoneless.date zl in let t = Timedesc.Zoneless.time zl in Printf.printf "date: %s time: %s\n" (Timedesc.Date.to_rfc3339 d) (Timedesc.Time.to_rfc3339 t); (* Attach a time zone *) let tz = Timedesc.Time_zone.make_exn "America/Chicago" in (match Timedesc.Zoneless.to_zoned ~tz zl with | Error _ -> print_endline "DST gap" | Ok dt -> Printf.printf "zoned: %s\n" (Timedesc.to_rfc3339 dt))); (* Handle either zoned or zone-less input *) (match Timedesc.Zoneless.maybe_zoneless_of_iso8601 "2024-09-01T08:00:00Z" with | Ok (`Zoned dt) -> Printf.printf "zoned UTC: %s\n" (Timedesc.to_rfc3339 dt) | Ok (`Zoneless _) -> print_endline "no zone" | Error msg -> Printf.printf "error: %s\n" msg) (* Output: date: 2024-09-01 time: 08:00:00 zoned: 2024-09-01T08:00:00-05:00 zoned UTC: 2024-09-01T08:00:00+00:00 *) ``` -------------------------------- ### Define Multi-field Calendar Patterns with Timere.pattern Source: https://context7.com/daypack-dev/timere/llms.txt Use `pattern` to match specific years, months, days, weekdays, hours, minutes, seconds, and nanoseconds. Empty constraint lists match any value for that field. Negative day values count from the end of the month. ```ocaml let () = let open Timere in (* Last day of every month at noon, in 2024 *) let expr = years [2024] &&& pattern ~days:[-1] ~hours:[12] ~minutes:[0] ~seconds:[0] () in (match resolve expr with | Error msg -> failwith msg | Ok s -> s |> OSeq.take 3 |> Seq.iter (fun iv -> Printf.printf "%s\n" (Timedesc.Interval.to_string iv))); (* Weekday range: Monday through Friday, 9am–9am (full day) *) let workdays = pattern ~weekday_ranges:[`Range_inc (`Mon, `Fri)] () in (match resolve (years [2024] &&& months [1] &&& workdays) with | Error msg -> failwith msg | Ok s -> let count = OSeq.fold (fun acc _ -> acc + 1) 0 s in Printf.printf "working days in Jan 2024: %d\n" count) (* Output: [2024 Jan 31 12:00:00 +00:00:00, 2024 Jan 31 12:00:00 +00:00:01) [2024 Feb 29 12:00:00 +00:00:00, 2024 Feb 29 12:00:00 +00:00:01) [2024 Mar 31 12:00:00 +00:00:00, 2024 Mar 31 12:00:00 +00:00:01) working days in Jan 2024: 23 *) ``` -------------------------------- ### Timedesc.make / Timedesc.make_exn Source: https://context7.com/daypack-dev/timere/llms.txt Constructs a time-zone-aware date-time from year, month, day, hour, minute, second, and nanosecond components. It handles DST gaps and can return an error for invalid combinations. It also supports nanosecond precision. ```APIDOC ## Timedesc.make / Timedesc.make_exn ### Description Creates a `Timedesc.t` from year/month/day/hour/minute/second components and an optional time zone. Returns `Error` if the combination does not exist (e.g., the date falls inside a DST gap). The result may be ambiguous (two possible UTC mappings) during a DST fold-back; use `to_timestamp` to detect this. ### Method `Timedesc.make` or `Timedesc.make_exn` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters for `make` and `make_exn` - **tz** (`Timedesc.Time_zone.t` option) - The time zone to use. If `None`, UTC is assumed. - **year** (int) - The year. - **month** (int) - The month (1-12). - **day** (int) - The day of the month. - **hour** (int) - The hour (0-23). - **minute** (int) - The minute (0-59). - **second** (int) - The second (0-59). - **ns** (int, optional) - The nanoseconds (0-999,999,999). Defaults to 0. - **offset_from_utc** (`Timedesc.Span.t` option) - Used with `make_unambiguous` to explicitly set the UTC offset. ### Request Example ```ocaml let () = let tz = Timedesc.Time_zone.make_exn "America/New_York" in (* Ordinary construction *) (match Timedesc.make ~tz ~year:2024 ~month:3 ~day:10 ~hour:10 ~minute:0 ~second:0 () with | Ok dt -> Printf.printf "ok: %s\n" (Timedesc.to_rfc3339 dt) | Error e -> Printf.printf "error: %s\n" (Timedesc.string_of_error e)); (* DST gap: 2024-03-10 02:30 does not exist in America/New_York *) (match Timedesc.make ~tz ~year:2024 ~month:3 ~day:10 ~hour:2 ~minute:30 ~second:0 () with | Error _ -> print_endline "correctly rejected non-existent DST time" | Ok _ -> print_endline "unexpected success"); (* Nanosecond precision *) let dt = Timedesc.make_exn ~tz ~year:2024 ~month:6 ~day:1 ~hour:12 ~minute:0 ~second:0 ~ns:500_000_000 () in Printf.printf "ns=%d\n" (Timedesc.ns dt) ``` ### Response #### Success Response - `Ok dt` (`Timedesc.t`) - The constructed date-time value. #### Error Response - `Error e` (`Timedesc.string_of_error`) - An error message if the date-time is invalid or ambiguous. ### Response Example ``` ok: 2024-03-10T10:00:00-04:00 correctly rejected non-existent DST time ns=500000000 ``` ``` -------------------------------- ### Construct Calendar Dates Source: https://context7.com/daypack-dev/timere/llms.txt Create dates using Gregorian (`Ymd.make`), ISO week (`ISO_week_date.make`), or ISO ordinal (`ISO_ord.make_exn`) systems. `weekday` and `day_of_year` can be retrieved, and dates converted to RFC3339 format. ```ocaml let () = (* Gregorian date *) (match Timedesc.Date.Ymd.make ~year:2024 ~month:2 ~day:29 with | Ok d -> Printf.printf "weekday: %s\n" (Timedesc.Utils.abbr_string_of_weekday (Timedesc.Date.weekday d)); Printf.printf "day of year: %d\n" (Timedesc.Date.day_of_year d) | Error _ -> print_endline "invalid date") ``` ```ocaml let () = (* ISO week date: 2024-W09-4 (Thursday, week 9 of 2024) *) (match Timedesc.Date.ISO_week_date.make ~year:2024 ~week:9 ~weekday:`Thu with | Ok d -> let v = Timedesc.Date.ISO_week_date.view d in Printf.printf "ISO: %04d-W%02d-%d\n" v.year v.week (Timedesc.Utils.iso_int_of_weekday v.weekday) | Error _ -> print_endline "invalid ISO week date") ``` ```ocaml let () = (* ISO ordinal: day 60 of 2024 *) let d = Timedesc.Date.ISO_ord.make_exn ~year:2024 ~day_of_year:60 in Printf.printf "ordinal->gregorian: %s\n" (Timedesc.Date.to_rfc3339 d) ``` -------------------------------- ### Lookup and Construct Time Zones Source: https://context7.com/daypack-dev/timere/llms.txt Use `make` to look up time zones by IANA name or construct fixed-offset zones using `make_offset_only`. `available_time_zones` lists all supported names. `make_exn` can be used for known names like 'UTC'. ```ocaml let () = (* Named time zone *) (match Timedesc.Time_zone.make "Pacific/Auckland" with | None -> print_endline "unknown" | Some tz -> Printf.printf "tz name: %s\n" (Timedesc.Time_zone.name tz)) ``` ```ocaml let () = (* Fixed offset UTC+5:30 (India) *) let offset = Timedesc.Span.For_human.make_exn ~hours:5 ~minutes:30 () (match Timedesc.Time_zone.make_offset_only offset with | None -> print_endline "offset too large" | Some tz -> Printf.printf "fixed tz: %s\n" (Timedesc.Time_zone.name tz)) ``` ```ocaml let () = (* UTC shorthand *) let tz_utc = Timedesc.Time_zone.make_exn "UTC" Printf.printf "utc equal: %b\n" (Timedesc.Time_zone.equal tz_utc Timedesc.Time_zone.utc) ``` ```ocaml let () = (* List first 5 available names *) Timedesc.Time_zone.available_time_zones |> List.filteri (fun i _ -> i < 5) |> List.iter print_endline ``` -------------------------------- ### Chunking and Slicing Intervals with Timere Source: https://context7.com/daypack-dev/timere/llms.txt Use `chunk` to split intervals at year/month boundaries or by fixed duration. Apply sequence operations like `take`, `nth`, and `drop` to the resulting chunks. The `chunk` function takes a boundary type and a function to process each chunk. ```ocaml let () = let open Timere in (* Get the first Monday of each month in 2024 *) let first_monday_each_month = chunk `At_month_boundary (fun months_chunks -> (* within each month-chunk, take only the first Monday *) take 1 (chunk `Disjoint_intervals (fun days -> nth_weekday_of_month 1 `Mon |> fun _ -> days) (years [2024])) (years [2024]) in ignore first_monday_each_month; (* Simpler: chunk year 2024 by month, take first interval *) let yearly = years [2024] in let by_month = chunk `At_month_boundary (fun c -> first c) yearly in (match resolve (Unchunk by_month) with | Error msg -> failwith msg | Ok s -> s |> OSeq.take 3 |> Seq.iter (fun iv -> Printf.printf "%s\n" (Timedesc.Interval.to_string iv))) ``` -------------------------------- ### Construct Time-of-Day Source: https://context7.com/daypack-dev/timere/llms.txt Create `Time.t` values with hour, minute, second, and nanosecond precision using `make_exn`. Handles leap seconds and 24:00:00. Can be converted to a span since midnight. Invalid hours trigger an error. ```ocaml let () = let t = Timedesc.Time.make_exn ~hour:23 ~minute:59 ~second:59 ~ns:999_999_999 () let v = Timedesc.Time.view t Printf.printf "%02d:%02d:%02d.%09d\n" v.hour v.minute v.second v.ns ``` ```ocaml let () = (* Convert to span since midnight *) let span = Timedesc.Time.to_span t Printf.printf "span seconds: %Ld\n" (Timedesc.Span.get_s span) ``` ```ocaml let () = (* Error cases *) (match Timedesc.Time.make ~hour:25 ~minute:0 ~second:0 with | Error (`Invalid_hour h) -> Printf.printf "bad hour: %d\n" h | _ -> ()) ``` -------------------------------- ### Timedesc.Span.For_human.make_exn / Timedesc.Span.For_human.view Source: https://context7.com/daypack-dev/timere/llms.txt Constructs a Span.t from days/hours/minutes/seconds/ns components in a human-readable way. `view` decomposes a span back into those fields. ```APIDOC ## Timedesc.Span.For_human.make_exn / Timedesc.Span.For_human.view ### Description Constructs a `Span.t` from days/hours/minutes/seconds/ns components in a human-readable way. `view` decomposes a span back into those fields. ### Method OCaml function calls ### Parameters `make_exn` accepts optional arguments for `sign`, `days`, `hours`, `minutes`, `seconds`, `ns`. `make_frac_exn` accepts optional arguments for `sign`, `days`, `hours`, `minutes`, `seconds`, `ns`. `view` accepts a `Span.t`. ### Request Example ```ocaml let () = (* "2 hours 15 minutes" *) let s1 = Timedesc.Span.For_human.make_exn ~hours:2 ~minutes:15 () (* "1.5 hours" using fractional constructor *) let s2 = Timedesc.Span.For_human.make_frac_exn ~hours:1.5 () let v = Timedesc.Span.For_human.view s2 (* Arithmetic *) let s3 = Timedesc.Span.(s1 + s2) (* Negative span *) let neg = Timedesc.Span.For_human.make_exn ~sign:`Neg ~hours:1 () ``` ### Response #### Success Response Returns a `Span.t` or a view of the span's components. #### Response Example ```ocaml (* Output from example code: *) seconds = 8100 hours=1 minutes=30 total string: 3 hours 45 mins 0 secs neg: -3600 ``` ``` -------------------------------- ### Temporal Transformations with Timere.shift and Timere.lengthen Source: https://context7.com/daypack-dev/timere/llms.txt Use `shift` to move intervals forward or backward by a `Span.t`. Use `lengthen` to extend every interval's end by a fixed duration. These functions are useful for adjusting existing time intervals. ```ocaml let () = let open Timere in (* Every Monday, shifted forward by 2 hours *) let base = weekdays [`Mon] in let offset = Timedesc.Span.For_human.make_exn ~hours:2 () in let shifted = shift offset base in (* Every Monday extended to cover 4 hours from midnight *) let duration = Timedesc.Span.For_human.make_exn ~hours:4 () in let lengthened = lengthen duration base in (match resolve (years [2024] &&& months [1] &&& shifted) with | Error msg -> failwith msg | Ok s -> s |> OSeq.take 1 |> Seq.iter (fun iv -> Printf.printf "shifted : %s\n" (Timedesc.Interval.to_string iv))); (match resolve (years [2024] &&& months [1] &&& lengthened) with | Error msg -> failwith msg | Ok s -> s |> OSeq.take 1 |> Seq.iter (fun iv -> Printf.printf "lengthened: %s\n" (Timedesc.Interval.to_string iv))) ``` -------------------------------- ### Timedesc.Time.make_exn Source: https://context7.com/daypack-dev/timere/llms.txt Creates a Time.t representing an hour/minute/second value with optional nanosecond precision. Leap second (second=60) and 24:00:00 are handled specially. ```APIDOC ## Timedesc.Time.make_exn ### Description Creates a `Time.t` representing an hour/minute/second value with optional nanosecond precision. Leap second (second=60) and 24:00:00 are handled specially. ### Method OCaml function calls ### Parameters `make_exn` accepts optional arguments for `hour`, `minute`, `second`, `ns`. `make` accepts optional arguments for `hour`, `minute`, `second`, `ns` and returns a result type. ### Request Example ```ocaml let t = Timedesc.Time.make_exn ~hour:23 ~minute:59 ~second:59 ~ns:999_999_999 () let v = Timedesc.Time.view t (* Convert to span since midnight *) let span = Timedesc.Time.to_span t (* Error cases *) let () = match Timedesc.Time.make ~hour:25 ~minute:0 ~second:0 () with | Error (`Invalid_hour h) -> Printf.printf "bad hour: %d\n" h | _ -> () ``` ### Response #### Success Response Returns a `Time.t` representing the constructed time. #### Response Example ```ocaml (* Output from example code: *) 23:59:59.999999999 span seconds: 86399 bad hour: 25 ``` ``` -------------------------------- ### Parse ISO 8601 and Print RFC 3339 Source: https://context7.com/daypack-dev/timere/llms.txt Parses ISO 8601 strings with varying precision and prints RFC 3339 / ISO 8601 strings. Includes variants for millisecond, microsecond, and nanosecond precision, as well as HTTP date format (RFC 9110). ```ocaml let () = (* Parse ISO 8601 *) (match Timedesc.of_iso8601 "2024-06-15T08:30:00.123456789+05:30" with | Error msg -> Printf.printf "parse error: %s\n" msg | Ok dt -> Printf.printf "ns = %d\n" (Timedesc.ns dt); Printf.printf "rfc3339 = %s\n" (Timedesc.to_rfc3339 dt); Printf.printf "rfc3339ms = %s\n" (Timedesc.to_rfc3339_milli dt); Printf.printf "rfc3339ns = %s\n" (Timedesc.to_rfc3339_nano dt)); (* RFC 9110 / HTTP date parsing *) (match Timedesc.of_rfc9110 "Sun, 15 Jun 2024 08:30:00 GMT" with | Error msg -> Printf.printf "http parse error: %s\n" msg | Ok dt -> Printf.printf "http: %s\n" (Timedesc.to_rfc9110 dt)) ``` -------------------------------- ### Construct Time-Zone-Aware Date-Time with Timedesc.make Source: https://context7.com/daypack-dev/timere/llms.txt Creates a Timedesc.t from date and time components with an optional time zone. Handles DST gaps and supports nanosecond precision. Use `to_timestamp` to detect ambiguity during DST fold-backs. ```ocaml let () = let tz = Timedesc.Time_zone.make_exn "America/New_York" in (* Ordinary construction *) (match Timedesc.make ~tz ~year:2024 ~month:3 ~day:10 ~hour:10 ~minute:0 ~second:0 () with | Ok dt -> Printf.printf "ok: %s\n" (Timedesc.to_rfc3339 dt) | Error e -> Printf.printf "error: %s\n" (Timedesc.string_of_error e)); (* DST gap: 2024-03-10 02:30 does not exist in America/New_York *) (match Timedesc.make ~tz ~year:2024 ~month:3 ~day:10 ~hour:2 ~minute:30 ~second:0 () with | Error _ -> print_endline "correctly rejected non-existent DST time" | Ok _ -> print_endline "unexpected success"); (* Nanosecond precision *) let dt = Timedesc.make_exn ~tz ~year:2024 ~month:6 ~day:1 ~hour:12 ~minute:0 ~second:0 ~ns:500_000_000 () in Printf.printf "ns=%d\n" (Timedesc.ns dt) ``` -------------------------------- ### Compose Timere Expressions with Set-Algebraic Combinators Source: https://context7.com/daypack-dev/timere/llms.txt Combine Timere expressions using `&&&` (intersection), `|||` (union), and `not` (complement). The `inter` and `union` functions accept lists, while the infix operators are binary shorthands. ```ocaml let () = let open Timere in (* Business hours: Mon-Fri, 9am-5pm, excluding lunch 12-1pm *) let weekdays_expr = pattern ~weekday_ranges:[`Range_inc (`Mon, `Fri)] () in let morning = hms_intervals (Timedesc.Time.make_exn ~hour:9 ~minute:0 ~second:0 ()) (Timedesc.Time.make_exn ~hour:12 ~minute:0 ~second:0 ()) in let afternoon = hms_intervals (Timedesc.Time.make_exn ~hour:13 ~minute:0 ~second:0 ()) (Timedesc.Time.make_exn ~hour:17 ~minute:0 ~second:0 ()) in let business_hours = weekdays_expr &&& (morning ||| afternoon) in (* Jan 2024 business hours *) let expr = years [2024] &&& months [1] &&& business_hours in (match resolve expr with | Error msg -> failwith msg | Ok s -> let count = OSeq.fold (fun acc _ -> acc + 1) 0 s in (* 23 work days × 2 intervals (morning + afternoon) = 46 *) Printf.printf "business intervals in Jan 2024: %d\n" count) (* Output: business intervals in Jan 2024: 46 *) ``` -------------------------------- ### Custom Timedesc String Formatting Source: https://context7.com/daypack-dev/timere/llms.txt Formats a Timedesc.t using a printf-style format string. Supports various date, time, and timezone components. Also shows how to extract ISO week date information. ```ocaml let () = let tz = Timedesc.Time_zone.make_exn "Asia/Tokyo" in let dt = Timedesc.make_exn ~tz ~year:2024 ~month:12 ~day:25 ~hour:14 ~minute:5 ~second:9 () in (* Default format *) Printf.printf "%s\n" (Timedesc.to_string dt); (* Custom: "Wed 25 Dec 2024 02:05 PM" *) Printf.printf "%s\n" (Timedesc.to_string ~format:"{wday:Xxx} {day:0X} {mon:Xxx} {year} {12hour:0X}:{min:0X} {am/pm:XX}" dt); (* ISO week date info *) let iw = Timedesc.iso_week dt in Printf.printf "ISO week %d of year %d\n" (Timedesc.ISO_week.week iw) (Timedesc.ISO_week.year iw) ``` -------------------------------- ### Parse Natural Language Time and Duration Strings Source: https://context7.com/daypack-dev/timere/llms.txt Parses time-of-day strings into Timedesc.Time.t and duration/span strings into Timedesc.Span.t. Handles specific cases like '24:00' and standard duration formats. ```ocaml let () = (* Parse time of day *) (match Timere_parse.hms "14:30" with | Error msg -> Printf.printf "hms error: %s\n" msg | Ok t -> Printf.printf "hour=%d min=%d\n" (Timedesc.Time.hour t) (Timedesc.Time.minute t)); (* Parse "24:00" — treated as 23:59:59.999999999 *) (match Timere_parse.hms "24:00" with | Error msg -> Printf.printf "error: %s\n" msg | Ok t -> Printf.printf "is_end_of_day: %b\n" (Timedesc.Time.hour t = 23)); (* Parse duration/span *) (match Timere_parse.span "2 hours 30 minutes" with | Error msg -> Printf.printf "span error: %s\n" msg | Ok sp -> Printf.printf "total seconds: %Ld\n" (Timedesc.Span.get_s sp)) (* Output: hour=14 min=30 is_end_of_day: true total seconds: 9000 *) ``` -------------------------------- ### Construct Unambiguous Date-Time with Explicit UTC Offset Source: https://context7.com/daypack-dev/timere/llms.txt Constructs a date-time with an explicit UTC offset, validating it against an optional time zone. Useful for parsing data that includes both a TZ name and a numeric offset. Rejects incorrect offsets for the given date and time zone. ```ocaml let () = let tz = Timedesc.Time_zone.make_exn "Europe/Paris" in (* Paris observes UTC+2 during summer (DST on) *) let offset = Timedesc.Span.For_human.make_exn ~hours:2 () in (match Timedesc.make_unambiguous ~tz ~year:2024 ~month:8 ~day:15 ~hour:14 ~minute:0 ~second:0 ~offset_from_utc:offset () with | Ok dt -> Printf.printf "%s\n" (Timedesc.to_rfc3339 dt) | Error e -> Printf.printf "error: %s\n" (Timedesc.string_of_error e)); (* Wrong offset for the date — UTC+1 is winter time, rejected *) let bad_offset = Timedesc.Span.For_human.make_exn ~hours:1 () in (match Timedesc.make_unambiguous ~tz ~year:2024 ~month:8 ~day:15 ~hour:14 ~minute:0 ~second:0 ~offset_from_utc:bad_offset () with | Error _ -> print_endline "rejected: wrong offset for summer" | Ok _ -> print_endline "unexpected") ``` -------------------------------- ### Evaluate Sub-expressions in a Specific Time Zone with Timere.with_tz Source: https://context7.com/daypack-dev/timere/llms.txt Use `with_tz` to wrap a Timere expression, ensuring pattern matching is performed relative to a specified time zone. This is essential for solving cross-timezone intersection problems. ```ocaml let () = let open Timere in let tz_sydney = Timedesc.Time_zone.make_exn "Australia/Sydney" in let tz_new_york = Timedesc.Time_zone.make_exn "America/New_York" in let office_hours tz = with_tz tz (hms_intervals (Timedesc.Time.make_exn ~hour:9 ~minute:0 ~second:0 ()) (Timedesc.Time.make_exn ~hour:17 ~minute:0 ~second:0 ())) in (* Find overlapping office hours: Sydney 9-5 ∩ New York 9-5 *) let expr = years [2024] &&& months [7] &&& days [1] &&& office_hours tz_sydney &&& office_hours tz_new_york in (match resolve expr with | Error msg -> failwith msg | Ok s -> (match s () with | Seq.Nil -> print_endline "No overlap (expected)" | Seq.Cons (iv, _) -> Printf.printf "Overlap: %s\n" (Timedesc.Interval.to_string iv))) (* Sydney is UTC+10, New York is UTC-4 in July: 14-hour gap → no overlap *) ```