Suppose your application receives bookings as timestamp strings and needs to offer the time left in a working day. Start with an opening window, turn each booking into occupied time, then subtract it. Keep an explicit Z or numeric offset in each timestamp so bookings from different offsets can be compared.
The pipeline§
The booking exchange source separates input/output in main.roc from the calculation in BookingExchange.roc. After getting the examples, run:
roc examples/booking_exchange/main.roc
The application follows five steps:
ExactInterval.parsevalidates the opening and booking strings.ExactInterval.spangives each interval’s timeline span.Coverage.from_spanscombines the occupied spans.Coverage.complement_withinfinds the free pieces inside the opening span.The application formats their endpoints as canonical UTC timestamps.
For a 09:00–17:00 opening and a 10:00–12:00 booking, the free windows are 09:00–10:00 and 12:00–17:00. Each span includes its start and excludes its end; a booking ending at noon doesn’t occupy noon onward.
Keep the gaps§
Coverage keeps every separate piece of time. It merges overlapping or touching bookings, so you don’t have to remove duplicate occupied time before finding availability.
That merge loses booking identity. If two customers both book 10:00–12:00, their combined coverage is still one span. Keep an EventCollection alongside coverage when you need to report conflicts or identify whose booking contributed the time.
Know what can fail§
An interval needs a start earlier than its end. Reversed endpoints, an empty interval and malformed timestamps return errors; the parser won’t swap endpoints or guess a timezone.
The timestamp profile accepts microseconds. Input with finer precision is rejected rather than truncated, and arithmetic near the signed coordinate limits is checked. Profiles and limits explains how to distinguish invalid input from valid forms the selected parser doesn’t support.
Store standard values§
When saving availability, keep each free span and serialize its endpoints. Your application chooses the surrounding collection format. A single earliest-start/latest-end pair would fill the gaps you’ve just calculated.
The catalogue storage example saves EDTF date descriptions and RFC 3339 timestamps in application-owned fields, then parses them again. The formats' serializers are the storage boundary; debug inspection text is for diagnostics.
For an expiry check, the clock deadline example reads the clock in its platform root and passes that reading to a pure comparison. Its saved JSON describes the check at that recorded time. Loading the JSON later doesn’t perform a new check.
API reference§
Start with ExactInterval, OffsetTimestamp and Coverage in the API map. Repository links above show current source; the release archive and API pages show the version you’re using.