time: wall-clock DateTime, TimeOfDay and fixed UTC offsets #387

Closed
opened 2026-10-19 22:05:39 +00:00 by orion · 3 comments
Collaborator

Context

Slice 2 of FIRST-PARTY.md gap 11 ("a wall-clock date and time, zones"): the wall-clock types and fixed UTC offsets, without a time zone database. Needed by every database driver's timestamp/timestamptz, S3 and HTTP. Depends on the Date/TimeParseError/Timestamp.parse slice (#111).

Design (decided by the loop)

In std/time, none in the prelude, none reaching a capability (add to capabilityOfImport in compiler/src/package/archive.trb and compiler/tests/capability.test.trb):

  • TimeOfDay: hour 0-23, minute, second 0-59, nanosecond; private nanoseconds-of-day field; of(hour, minute, second, nanosecond = 0), accessors, Compare, Equals, Hash, Show (08:15:00.25), parse.
  • UtcOffset: whole seconds from UTC, range -23:59:59..+23:59:59 (RFC 3339 writes minutes only, but databases send seconds); utc, ofMinutes, ofSeconds, show (Z-less: +02:00, +00:00), parse (+hh:mm, Z).
  • DateTime: a Date and a TimeOfDay with no offset or zone (a "local" date and time); Compare, Equals, Hash, Show (2026-09-27T08:15:00), parse, plus(Duration), Date/TimeOfDay accessors.
  • OffsetDateTime: DateTime plus UtcOffset; parse of RFC 3339 keeping the written offset; instant(): Result<Timestamp, TimeParseError>; Timestamp.at(offset: UtcOffset): OffsetDateTime; show writes RFC 3339 with the offset (2026-09-27T10:15:00+02:00) so parse(show(x)) == x. Equals compares the fields (same instant, different offset is not equal); Compare by instant.
  • No named zones, no daylight saving: that is the zones issue.

Acceptance criteria

  • The four types and their parse/show as designed, in std/time
  • Tests in std/time/tests/: midnight and 23:59:59.999999999, invalid fields refused, offsets +14:00, -12:00, +05:45, Z, conversion OffsetDateTime <-> Timestamp across the epoch and a leap day, DateTime.plus over month/year borders, show/parse round trips
  • Capability-free listing and test as above
  • docs/standard-library/time.md updated, skills/ regenerated, FIRST-PARTY.md gap 11 progress noted
  • No seed impact (no syntax, native, driver flag or std name looked up by the compiler); at most two Conventional Commits, tier A green in forge CI

Dependencies

#111 (Date, TimeParseError, Timestamp.parse).

## Context Slice 2 of [FIRST-PARTY.md gap 11](https://git.torb.dev/torbscript/language/src/commit/393ef2608e4a60b8ff76d8b6b408951b822d887d/docs/design/FIRST-PARTY.md#L271) ("a wall-clock date and time, zones"): the wall-clock types and fixed UTC offsets, without a time zone database. Needed by every database driver's `timestamp`/`timestamptz`, S3 and HTTP. Depends on the `Date`/`TimeParseError`/`Timestamp.parse` slice (#111). ## Design (decided by the loop) In `std/time`, none in the prelude, none reaching a capability (add to `capabilityOfImport` in `compiler/src/package/archive.trb` and `compiler/tests/capability.test.trb`): - `TimeOfDay`: hour 0-23, minute, second 0-59, nanosecond; private nanoseconds-of-day field; `of(hour, minute, second, nanosecond = 0)`, accessors, `Compare, Equals, Hash, Show` (`08:15:00.25`), `parse`. - `UtcOffset`: whole seconds from UTC, range -23:59:59..+23:59:59 (RFC 3339 writes minutes only, but databases send seconds); `utc`, `ofMinutes`, `ofSeconds`, `show` (`Z`-less: `+02:00`, `+00:00`), `parse` (`+hh:mm`, `Z`). - `DateTime`: a `Date` and a `TimeOfDay` with no offset or zone (a "local" date and time); `Compare, Equals, Hash, Show` (`2026-09-27T08:15:00`), `parse`, `plus(Duration)`, `Date`/`TimeOfDay` accessors. - `OffsetDateTime`: `DateTime` plus `UtcOffset`; `parse` of RFC 3339 keeping the written offset; `instant(): Result<Timestamp, TimeParseError>`; `Timestamp.at(offset: UtcOffset): OffsetDateTime`; `show` writes RFC 3339 with the offset (`2026-09-27T10:15:00+02:00`) so `parse(show(x)) == x`. `Equals` compares the fields (same instant, different offset is not equal); `Compare` by instant. - No named zones, no daylight saving: that is the zones issue. ## Acceptance criteria - [ ] The four types and their parse/show as designed, in `std/time` - [ ] Tests in `std/time/tests/`: midnight and 23:59:59.999999999, invalid fields refused, offsets `+14:00`, `-12:00`, `+05:45`, `Z`, conversion `OffsetDateTime` <-> `Timestamp` across the epoch and a leap day, `DateTime.plus` over month/year borders, show/parse round trips - [ ] Capability-free listing and test as above - [ ] `docs/standard-library/time.md` updated, `skills/` regenerated, FIRST-PARTY.md gap 11 progress noted - [ ] No seed impact (no syntax, native, driver flag or std name looked up by the compiler); at most two Conventional Commits, tier A green in forge CI ## Dependencies #111 (Date, TimeParseError, Timestamp.parse).
Author
Collaborator

[loop:torbscript] intake: in scope, no duplicate, dependencies closed (#61 / #111), definition of ready met (goal, acceptance criteria, design, no seed impact). Set ready. next: implement

[loop:torbscript] intake: in scope, no duplicate, dependencies closed (#61 / #111), definition of ready met (goal, acceptance criteria, design, no seed impact). Set `ready`. next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261021 until 2026-10-21T04:00:43Z

[loop:torbscript] claim implement by session:loop-torbscript-20261021 until 2026-10-21T04:00:43Z
argus closed this issue 2026-10-20 22:39:46 +00:00
Author
Collaborator

[loop:torbscript] implement: PR #395 opened (one commit, feat(time)), forge CI green (tier A, gates, bootstrap, pdisc; tier B skipped by the change filter). TimeOfDay, UtcOffset, DateTime, OffsetDateTime and Timestamp.at in std/time, 36 new tests, capability listing and test, time.md, regenerated skills/, FIRST-PARTY gap 11. No seed impact. Worker token usage: not measurable from inside the worker session. next: review

[loop:torbscript] implement: PR https://git.torb.dev/torbscript/language/pulls/395 opened (one commit, `feat(time)`), forge CI green (tier A, gates, bootstrap, pdisc; tier B skipped by the change filter). TimeOfDay, UtcOffset, DateTime, OffsetDateTime and Timestamp.at in std/time, 36 new tests, capability listing and test, time.md, regenerated skills/, FIRST-PARTY gap 11. No seed impact. Worker token usage: not measurable from inside the worker session. next: review
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#387
No description provided.