Skip to content

fix: a date-only input is the written date at default_time in UTC - #14

Merged
jqnatividad merged 2 commits into
mainfrom
date-only-utc-anchor
Oct 26, 2026
Merged

jqnatividad merged 2 commits into
mainfrom
date-only-utc-anchor

Conversation

@jqnatividad

Copy link
Copy Markdown
Collaborator

A date-only input (2021-02-21, July 4, 2005, 04/07/2005, …) got its time of day from default_time converted into the timezone today, and that wall-clock time was then attached to the written date. So the result depended on the day it ran, and it could land on another date:

  • Year-round, west of UTC: with default_time at midnight, which is what qsv datefmt uses, every zone west of UTC returned the next day. America/Los_Angeles turned "July 4, 2005" into 2005-07-05, and so did "2005-07-04 PST" even when parsed with Utc.
  • Seasonally, around DST: when today's offset differed from the written date's, the time shifted. With Europe/Athens, a July date moved to the previous day once Athens left summer time, so qsv's datefmt_input_tz test went red at 2026-10-26 00:00 UTC.

Fix

All eight date-only parsers (ymd, ymd_z, month_ymd, month_mdy, month_dmy, slash_mdy, slash_dmy, slash_ymd) now return Utc.from_utc_datetime(&date.and_time(default_time)): the written date is the UTC date, at default_time read as UTC. This also drops a Utc::now() call from every date-only parse. The public docs now say so.

Behavior change → 0.20.0

parse() and parse_with_timezone() use the current time as default_time. They used to give a date-only input the current wall-clock time in the input zone, and now give it the current UTC time, so its UTC date is always the written date. The results differ only when converting the current moment into the zone crosses midnight. Four existing tests (ymd_z, parse_in_local, parse_with_timezone_in_utc, parse_unambiguous_dmy) encoded the old arithmetic, and only agreed with the old code because they recomputed the same shift. They are updated.

Tests

  • New date_only_is_the_written_date_at_default_time_utc uses fixed times (00:00 and 23:30), not Utc::now(). It covers every date-only parser in UTC, UTC−8, UTC+3, America/Los_Angeles, Europe/Athens and Pacific/Auckland. Mutation-checked one input at a time: each of the 8 fails on the old code.
  • The suite passes under TZ=UTC, Pacific/Kiritimati (UTC+14), Pacific/Pago_Pago (UTC−11), America/Los_Angeles and Europe/Athens. Clippy with -D warnings and cargo fmt --check are clean.

On the qsv side, datefmt_input_tz passes again with this change, and datefmt_tz_inout turns out to have encoded the next-day bug: US/Hawaii expected July 5. The qsv PR follows the 0.20.0 release.

🤖 Generated with Claude Code

jqnatividad and others added 2 commits October 25, 2026 20:24
A date-only input (2021-02-21, July 4 2005, 04/07/2005, ...) took its time
of day from default_time converted into the timezone *today*, then
re-attached that wall-clock time to the written date. The result depended on
the day it ran and could land on another date:

- When today's offset differs from the written date's (DST), the time
  shifted: Europe/Athens with a July date moved to the previous day once
  Athens left summer time, so qsv's datefmt_input_tz test went red on
  2026-10-26 00:00 UTC.
- When the conversion crossed midnight, the date moved: with default_time
  at midnight (qsv datefmt), every zone west of UTC returned the next day,
  all year (America/Los_Angeles: "July 4, 2005" -> 2005-07-05).

All eight date-only parsers (ymd, ymd_z, month_ymd, month_mdy, month_dmy,
slash_mdy, slash_dmy, slash_ymd) now return
Utc.from_utc_datetime(&date.and_time(default_time)): the written date as
the UTC date, matching parse_with's "use provided default naive time".
This also drops a Utc::now() call from every date-only parse.

Behavior change: parse()/parse_with_timezone() (default_time = now) used to
give a date-only input the current wall-clock time in the input zone; it
now gets the current UTC time, so its UTC date is always the written date.
The ymd_z, parse_in_local, parse_with_timezone_in_utc and
parse_unambiguous_dmy expectations encoded the old arithmetic (and only
agreed with it by recomputing the same shift) and are updated.

New test date_only_is_the_written_date_at_default_time_utc uses fixed times
(00:00, 23:30) and covers every date-only parser in UTC, UTC-8, UTC+3,
America/Los_Angeles, Europe/Athens and Pacific/Auckland; each input fails
on the old code. The suite passes under TZ=UTC, Pacific/Kiritimati,
Pacific/Pago_Pago, America/Los_Angeles and Europe/Athens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
parse(), parse_with_timezone(), parse_with_preference_and_timezone(),
parse_with() and Parse::new/new_with_preference said a timezone-less input
is parsed in Local or the supplied timezone. Since the previous commit that
holds only for inputs with a time of day; a date-only input is the written
date at the default time (current UTC time, midnight, or default_time) in
UTC. Document it on each, and that default_time is a UTC time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jqnatividad
jqnatividad merged commit 1004159 into main Oct 26, 2026
14 checks passed
@jqnatividad
jqnatividad deleted the date-only-utc-anchor branch October 26, 2026 00:34
jqnatividad added a commit to dathere/qsv that referenced this pull request Oct 26, 2026
…r 0.20.0) (#4920)

* fix: datefmt --input-tz keeps a date-only value's date (qsv-dateparser 0.20.0)

A date-only value (July 4, 2005; 2005-07-04; ...) took its time of day
from today's offset in qsv-dateparser 0.19.0. With --input-tz west of UTC
it landed on the next day, all year (America/Los_Angeles: July 4, 2005 ->
2005-07-05); east of UTC it shifted by up to an hour with the season, and
Europe/Athens moved a July date to the previous day once Athens left
summer time, turning datefmt_input_tz red on every CI job from 2026-10-26
00:00 UTC. qsv-dateparser 0.20.0 (dathere/qsv-dateparser#14) makes a
date-only input the written date at the default time in UTC.

- datefmt_tz_inout encoded the next-day bug (US/Hawaii expected July 5);
  corrected to July 4.
- New datefmt_date_only_input_tz_keeps_the_written_date: date-only values
  in five layouts under America/Los_Angeles, Europe/Athens and
  Pacific/Auckland print the bare written date. It, datefmt_input_tz and
  datefmt_tz_inout all fail on 0.19.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: cite #4920 in the datefmt CHANGELOG entry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant