Skip to content

DateHelper: accept ISO-8601 timestamps with optional fractional seconds - #98

Merged
projectdelta6 merged 4 commits into
mainfrom
dev/tolerant-server-date-parsing
Jul 2, 2026
Merged

DateHelper: accept ISO-8601 timestamps with optional fractional seconds#98
projectdelta6 merged 4 commits into
mainfrom
dev/tolerant-server-date-parsing

Conversation

@projectdelta6

Copy link
Copy Markdown
Collaborator

Problem

parseServerInstant / parseNaiveDateTime document that any explicit ISO-8601 offset parses — but SERVER_PATTERN_FULL_OFFSET demands exactly six fractional digits, so Laravel/Carbon toIso8601String() output (2026-07-02T12:09:58+00:00, no fraction) fell through every parser and returned null.

Caught in the field on Accelerate today: a real device login stored the user fine, but onboarding_completed_at / created_at arrived as null through NullableZonedDateTimeSerializer — silently, since the fields are nullable:

E DateHelper: parseServerInstant: failed to parse "2026-07-02T12:09:58+00:00" with any known format

The consuming backend has ~32 date fields emitting this format, and toIso8601String() is common across Laravel backends generally — hence fixing the parser once here rather than chasing every backend.

Fix — purely additive fallbacks

The strict parsers stay first, so any input that parsed before still parses identically (the legacy-behaviour suites pass unchanged). Only previously-failing inputs reach the new steps:

  • parseServerInstant: after the strict pattern, try DateTimeFormatter.ISO_OFFSET_DATE_TIME (fractional seconds optional, 0–9 digits; Z / ±HH:MM offsets) before the Carbon short-format fallback.
  • parseNaiveDateTimeInternal: try ISO_LOCAL_DATE_TIME after NAIVE_PATTERN_FULL, and ISO_OFFSET_DATE_TIME after SERVER_PATTERN_FULL_OFFSET.
  • KDocs updated to state fractional seconds are optional (1.6.1+).

Tests

New DateHelperIsoToleranceTest (10 cases): the literal field-failure string, fraction-less Z, millisecond precision, non-UTC offsets, still-working strict forms, garbage rejection, and the naive-chain equivalents. Full DateHelperUtil + DateHelperUtil-Serialization suites green.

Also included

  • Toolbox version → 1.6.1, composeBom → 2026.06.01 (+ README version refs).

🤖 Generated with Claude Code

jakeeilbeck and others added 4 commits June 18, 2026 16:02
parseServerInstant and parseNaiveDateTime documented that any explicit
ISO-8601 offset parses, but SERVER_PATTERN_FULL_OFFSET demands exactly
six fractional digits — so Laravel/Carbon toIso8601String() output
("2026-07-02T12:09:58+00:00", no fraction) fell through every parser
and silently returned null. Caught in the field on Accelerate: the user's
onboarding_completed_at/created_at arrived as null through
NullableZonedDateTimeSerializer while every other field parsed fine.

Add purely additive fallbacks so behaviour matches the docs:

- parseServerInstant: try DateTimeFormatter.ISO_OFFSET_DATE_TIME
  (fractional seconds optional, 0-9 digits) after the strict pattern,
  before the Carbon short form.
- parseNaiveDateTimeInternal: try ISO_LOCAL_DATE_TIME after
  NAIVE_PATTERN_FULL, and ISO_OFFSET_DATE_TIME after
  SERVER_PATTERN_FULL_OFFSET.

The strict parsers stay first, so anything that parsed before still
parses identically — the existing legacy-behaviour suites pass
unchanged. New DateHelperIsoToleranceTest covers the Carbon form,
fraction-less Z, millisecond precision, non-UTC offsets, and the
still-working strict forms.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@projectdelta6
projectdelta6 changed the base branch from develop to main July 2, 2026 12:44
@projectdelta6 projectdelta6 reopened this Jul 2, 2026
@projectdelta6
projectdelta6 requested a review from jakeeilbeck July 2, 2026 13:03
@projectdelta6
projectdelta6 merged commit bd7a7f6 into main Jul 2, 2026
1 check passed
@projectdelta6
projectdelta6 deleted the dev/tolerant-server-date-parsing branch July 2, 2026 13:27
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