Skip to content

Utc: parse ISO 8601 / RFC 3339, and format with fractions of a second #533

Closed

Description

@y2kbugger

Utc.to_iso_8601 formats an instant, but nothing parses one back, and the format drops fractions of a second.

What we needed while porting a Go service to 0.26.0-rc3: it keeps a ledger file of the droplets it created, written by Go with time.Time (RFC 3339 with nanoseconds, "2026-10-17T09:01:23.456789123Z", and "0001-01-01T00:00:00Z" for none). Reading it back in Roc means writing an RFC 3339 parser by hand. Times in JSON from other tools are the same: GitHub's published_at, systemd's timestamps, cloud APIs.

A sketch:

Utc.from_iso_8601 : Str -> Try(Utc, [InvalidTime(Str)])   # RFC 3339: Z or an offset, optional fraction
Utc.to_iso_8601_nanos : Utc -> Str                        # "2026-10-17T09:01:23.456789123Z"

The calendar arithmetic is already there (InternalDateTime), and Utc's signed range covers year 1. If it is out of scope for basic-cli, a line in Utc's docs saying so would also help.

Seen on 0.26.0-rc3.

Activity

  1. y2kbugger commented on Oct 21, 2026

    @y2kbugger
    Author

    Thanks for the pointer to roc-time; keeping parsing out of the host makes sense.

    We tried roc-time 0.3.0 (OffsetTimestamp.parse, then boundary) against our small hand-written parser on the times our files hold. Everything roc-time accepts agrees with ours exactly: .123456Z, .123Z, -04:00 offsets and Go's zero time 0001-01-01T00:00:00Z.

    The one gap: these files are written by Go's time.Time JSON encoding, which is RFC 3339 with up to nine fraction digits (time.RFC3339Nano), and roc-time refuses 2026-10-20T17:01:16.123456789Z with UnsupportedPrecision. Its docs say six digits at most is by design, so for now we keep our parser.

    That's roc-time's question rather than basic-cli's, so feel free to close this. If a nanosecond (RFC3339Nano) profile is in scope for roc-time, I'd be glad to open an issue there.

  2. y2kbugger commented on Oct 21, 2026

    @y2kbugger
    Author

    Closing: answered by #534, which documents the boundary (parsing belongs in a time package such as roc-time, not the native host).

  3. y2kbugger commented on Oct 21, 2026

    @y2kbugger
    Author

    A correction to the above: I checked the actual file rather than assuming. Our ledger holds no nine-digit times any more. The tool that now writes it rewrites every entry with millisecond fractions on each save, so the Go-written times were already gone. roc-time 0.3.0 would read everything we have today.

    So nine digits isn't a need for us, and I won't open anything on roc-time for it. We keep our small parser only because it covers the four things we use (parse, format, the start of a month, and Go's zero time), not because roc-time falls short.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions