Skip to content

fix(waterdata): naive datetime filters shifted an hour across the DST boundary#307

Draft
thodson-usgs wants to merge 1 commit into
DOI-USGS:mainfrom
thodson-usgs:fix/waterdata-datetime-dst
Draft

fix(waterdata): naive datetime filters shifted an hour across the DST boundary#307
thodson-usgs wants to merge 1 commit into
DOI-USGS:mainfrom
thodson-usgs:fix/waterdata-datetime-dst

Conversation

@thodson-usgs
Copy link
Copy Markdown
Collaborator

Problem

_format_api_dates resolved the local timezone once, as a frozen offset from "now":

local_timezone = datetime.now().astimezone().tzinfo   # e.g. timezone(-4h) in summer
... parsed.replace(tzinfo=local_timezone)             # applied to EVERY naive input

A fixed offset can't represent DST, so a naive datetime on a date whose DST status differs from today is shifted by an hour. Verified on an EDT (−04:00) machine:

time="2020-01-01 12:00:00"  ->  2020-01-01T16:00:00Z   # WRONG — January is EST (-05:00), should be 17:00:00Z

This skews the query window for get_continuous / get_field_measurements (time/begin/end) whenever the input date is in the other DST season.

Fix

Interpret a naive input with parsed.astimezone(), which presumes the system local zone and uses the DST rules for that input's own date, then convert to UTC. Inputs that already carry an explicit offset (Z/+HH:MM) are unchanged.

Verification

winter 2020-01-01 12:00 -> 2020-01-01T17:00:00Z   # now correct (EST -05:00)
summer 2020-07-01 12:00 -> 2020-07-01T16:00:00Z   # correct (EDT -04:00)
aware  +00:00            -> 2020-01-01T12:00:00Z   # offset honored
date-only / interval / duration  -> unchanged

16 existing date-formatting tests pass; ruff clean.

No new unit test: the bug only manifests when the test runner's local zone observes DST, so a portable assertion would require mocking the system tz. Verified manually as above.

🤖 Generated with Claude Code

…'s offset

_format_api_dates froze `datetime.now().astimezone().tzinfo` (today's UTC
offset) and applied it to every naive datetime input. A naive input on a date
whose DST status differs from today was shifted by an hour: on an EDT (-0400)
machine, time="2020-01-01 12:00:00" produced 2020-01-01T16:00:00Z, but January
is EST (-0500) so the correct value is 17:00:00Z. This skewed the query window
for get_continuous / get_field_measurements (time/begin/end) across DST
boundaries.

Use `parsed.astimezone()` to interpret a naive input in the system local zone
with the DST rules for its own date, then convert to UTC. Inputs that already
carry an explicit offset are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <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