An invoice due next month and a shift that crosses a clock change need different calculations. Here you’ll calculate a due date, then work out how many hours an overnight shift covers.
The commands below work from a checkout with a current Roc nightly. For released packages, get the same applications from the examples archive. Repository links show current source, which may be ahead of your release.
Invoice terms: calendar arithmetic§
A merchant issues an invoice on January 31 with payment due one calendar month later. February has no 31st, so the merchant’s terms clamp the date to the month’s last day. The invoice example applies that policy:
roc examples/invoice/main.roc
Payment terms: one calendar month, clamped to month end
Issued: 2025-01-31
Payment due: 2025-02-28
Calendar.Arithmetic shifts the calendar date with an explicit destination policy. If your business rule requires a missing day to be rejected, choose rejection instead. Adding a fixed number of seconds can’t express either rule reliably. Adding a month and subtracting one also needn’t recover the original date after clamping: February 28 doesn’t remember January 31.
Gregorian and Julian dates use their rules in every supported year, rather than modeling each country’s historical adoption. Year zero means 1 BCE. Converting between the calendars keeps the civil day; it doesn’t choose midnight or a timezone.
Overnight staffing: interpret a local selection§
A Melbourne team works from 22:00 to 06:00 across the spring clock change. The clock skips an hour, so the shift covers seven hours rather than eight. Run the staffing example:
roc examples/staffing/main.roc
Overnight staffing in Australia/Melbourne
Local shift: 22:00 to 06:00 across the spring clock change
Budget 7 hours per team member.
The application selects named-zone data from the optional package, validates it with ZoneRules.from_database, and asks which timeline positions have labels in the local shift. The library doesn’t consult your machine’s timezone. The data package’s manifest tells you which release and date range it covers.
A local selection means all positions whose clock labels fall in the chosen range. During a repeated hour, it can contain separate pieces; a skipped date can contain none. Keeping only the earliest and latest positions would fill gaps that weren’t selected.
Appointments need a choice§
An appointment at a repeated 01:30 is a different question: which occurrence did the person book? A resolver reports a repeated time as Fold, a skipped time as Gap, and a single match as Unique. Your application then applies the appointment’s policy. The repeated local time example compares the choices with selecting the whole repeated range.
The rules must cover enough time to find every possible match. If the query reaches beyond the data’s validity, it returns an error even when one candidate is visible. Select rules covering the request rather than treating that candidate as complete or assuming UTC.
Parse and present civil labels§
GregorianDate, ClockTime and LocalDateTime parse date and clock labels without assigning a zone. EnglishGregorian can display them as 7 Sep 2026, 09:30. Its minute/second choices reject nonzero omitted fields, so presentation won’t silently discard precision. The appointment display example shows these choices.
A displayed local label hasn’t been proved to exist in any particular zone. For a named-zone appointment, interpret it first and present the selected result, as in the named-zone appointment example.
Gregorian dates also provide weekday, ordinal-day and ISO week-date queries. The invoice report combines them with calendar arithmetic. Consult your release’s API pages for its available operations.
API reference§
Calendar.Arithmetic, Calendar.Date, LocalDateTime and ZoneRules are mapped in the API guide.