Skip to content

fix(time): parse layouts like Go's time.Parse - #255

Merged
paralin merged 1 commit into
s4wave:devfrom
cogentcore:fix/time-parse-layout
Oct 13, 2026
Merged

paralin merged 1 commit into
s4wave:devfrom
cogentcore:fix/time-parse-layout

Conversation

@rcoreilly

Copy link
Copy Markdown
Contributor

time.Parse and time.ParseInLocation were a stub built on the JS Date parser. They accepted values that do not match the layout (for example, "2025-05-15" parsed with RFC3339) and ignored the location for layouts like DateTime, using the host zone instead. github.com/BurntSushi/toml relies on Go's behavior: it tries a list of layouts in order and uses the first that parses, so the stub gave TOML dates and times the wrong type and value. ParseInLocation also did not accept a *Location held in a variable or struct field, which BurntSushi passes, so its parser failed to typecheck.

This replaces the stub with a port of Go's layout-driven parser from time/format.go: the same chunk tokenization, strict literal matching, fractional seconds (including implicit ones after the seconds field), numeric and named zones, day-of-year, range checks, and "extra text" errors, with ParseError messages that match Go's text. Zone offsets are matched against the given location, as in Go.

Related fixes in the same area:

  • ParseInLocation now accepts Location, VarRef, or null, as Date and Time.In already do.
  • ParseDuration is a port of Go's, so compound durations like "1m30s" and "-2h45m3.5s" parse. Its error messages now match Go's; one unit test expected "invalid duration" where Go reports "missing unit in duration", and is updated.
  • Date builds values with setUTCFullYear/setFullYear. The Date constructors map years 0-99 to 1900-1999, which broke time-only layouts that parse to year 0.
  • Format prints Z for any zero offset in the Z07:00 family, not only for the UTC location.
  • Duration.String always prints seconds once a duration is at least one second, and prints minutes whenever there are hours ("1h30m0s"), as Go does.

The new fixtures package_import_time_parse_layout and package_import_time_parse_location_field cover BurntSushi's layouts with matching and non-matching values, error text, other layout elements, ParseDuration, and *Location struct fields. The full compiler suite, the gs/time unit tests, and typecheck pass.

Replace the JS Date based Parse/ParseInLocation stub with a port of Go's
layout-driven parser, accept *Location values held in variables or fields,
port ParseDuration for compound durations, build Date values correctly for
years below 100, and format zero offsets as Z and whole-hour durations as
Go does.

Signed-off-by: Randall C. O'Reilly <oreilly@ucdavis.edu>
@paralin
paralin changed the base branch from master to dev October 13, 2026 22:19
@paralin
paralin merged commit 35ad72f into s4wave:dev Oct 13, 2026
7 checks passed
@paralin

paralin commented Oct 13, 2026

Copy link
Copy Markdown
Member

Landed on master as 9439851. I folded package_import_time_parse_location_field into package_import_time_parse_layout. In parseTime, a local fail helper replaces the eight [new Time(), newParseError(alayout, avalue, ...)] returns, the time at a parsed offset is computed once, and the field declarations and result branches have paragraph comments. I also renamed parseBad and layoutChunk to PascalCase and shared one TextEncoder in quoteParseValue.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants