From a46f1e5282fbc991874bf143a93c9224d499e874 Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Thu, 15 Oct 2026 05:18:05 +0000 Subject: [PATCH 1/2] fix(codes): read GST as Guam Standard Time, as the services do codes.timezones mapped GST to UTC+4 (Gulf Standard Time). The USGS time-zone codes and the WQX TimeZone domain both define GST as Guam Standard Time, UTC+10, so the DateTime columns that wqp.get_results() and waterdata.get_samples() append placed a time stamped GST at 10:00 local at 06:00 UTC instead of 00:00 UTC. utils.format_datetime shares the table. HDT, a USGS code for Hawaii-Aleutian Daylight Time (UTC-9), was missing and became NaT. --- NEWS.md | 2 ++ dataretrieval/codes/timezones.py | 15 +++++++++++---- tests/utils_test.py | 21 +++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 71fbb700c..dd30d7ebc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,5 @@ +**10/15/2026:** **Bug fix:** the `ActivityStartDateTime` and `Activity_StartDateTime` columns that `wqp.get_results()` and `waterdata.get_samples()` append, and the `datetime` column of `utils.format_datetime()`, read the time-zone code `GST` as Gulf Standard Time (UTC+4). The USGS time-zone codes and the WQX TimeZone domain both define `GST` as Guam Standard Time (UTC+10), so a sample collected on Guam at 10:00 local time was placed at 06:00 UTC instead of 00:00 UTC. `GST` is now UTC+10, and `HDT` (Hawaii-Aleutian Daylight Time, UTC-9), a USGS code that was missing from the table, now resolves instead of becoming `NaT`. + **10/13/2026:** Twenty columns that the Water Data OGC collections return are now named, documented parameters of the getter that returns them; before, they could be passed only through `**queryables`. `get_field_measurements()`: `control_condition`, `day`, `field_measurements_series_id`, `measurement_rated`, `month`, `reading_type`, `time_of_day`, `year`. `get_peaks()`: `qualifier`, `time_of_day`, `value`. `get_monitoring_locations()`: `revision_created`, `revision_modified`, `revision_note`. `get_combined_metadata()`: `data_gap_interval`, `reading_type`. `get_time_series_metadata()`: `data_gap_interval`, `parameter_description`. `get_field_measurements_metadata()`: `reading_type`. `get_channel()`: `channel_location_direction`. They are keyword-only, so every existing call, including one that passes arguments by position, sends the same request as before; `sublocation_identifier` (10/07) is keyword-only too. **Behavior change:** `statistics_begin` in `get_time_series_metadata()` and `method_category` in `get_continuous()`, added in 1.4.0, are now keyword-only too, so a call that passed either by position, or passed a later argument by position (from `thresholds` in `get_time_series_metadata()` and from `value` in `get_continuous()`), must pass it by name. **10/12/2026:** **Behavior change:** a date range passed as one `"start/end"` string, such as `time="2024-01-01T10:00:00/.."`, is now formatted like the list form `["2024-01-01T10:00:00", None]` in the `waterdata` and `ngwmn` OGC getters and in `waterdata.get_ratings()`. **Bug fix:** the string used to be sent unchanged, so the two forms could select different data: an offset was not converted to `Z`, and a date-only collection such as `daily` received times. A string now raises `ValueError` before any request is sent if a side is not a date (`time="2024-01-01/tomorrow"`), if it contains more than one `/`, or if either side is a duration (`"2024-01-01/P7D"`), which the services rejected with HTTP 400. An empty side is an open bound, and `"../.."` means no date filter. A lone duration such as `"P7D"` is unchanged. **Bug fix:** in `ngwmn.get_water_level()` and `waterdata.get_ratings()`, a range with an open start, such as `[None, "2016-01-01"]` or `"../2016-01-01"`, failed with HTTP 403 because those services' firewalls reject `../`. Both getters now send an empty start (`"/2016-01-01"`), which both services treat as open. The other Water Data getters still send `..`, because that API rejects an empty start. Fractional seconds, such as `2024-01-01T10:00:00.999Z`, are kept instead of truncated, and a minute-precision time (`2024-01-01T10:00Z`) and spaces around the `/` are accepted. **Behavior change:** a naive date or time is now UTC, as in pandas (`pd.to_datetime(..., utc=True)`) and `get_nearest_continuous()`, instead of the machine's local time, so `time=["2024-03-01", "2024-03-02"]` sends `2024-03-01T00:00:00Z/2024-03-02T00:00:00Z` on every machine. An aware value is converted to UTC, including in a date-only collection such as `daily`. For a local time, include the offset: `"2024-03-01T00:00:00-06:00"`. diff --git a/dataretrieval/codes/timezones.py b/dataretrieval/codes/timezones.py index 22907ebd9..004ba5114 100644 --- a/dataretrieval/codes/timezones.py +++ b/dataretrieval/codes/timezones.py @@ -1,9 +1,16 @@ -"""Time zone information.""" +"""Time zone information. + +Maps the time-zone abbreviations that services put beside a local date and +time to UTC offsets. Several abbreviations name more than one zone worldwide; +where they do, the entry follows the services' own code lists (the USGS +time-zone codes and the WQX TimeZone domain), so ``GST`` is Guam Standard +Time rather than Gulf Standard Time. +""" tz_str = """-1200 Y -1100 X NUT SST -1000 W CKT HAST HST TAHT TKT --0900 V AKST GAMT GIT HADT HNY +-0900 V AKST GAMT GIT HADT HDT HNY -0800 U AKDT CIST HAY HNP PST PT -0700 T HAP HNR MST PDT -0600 S CST EAST GALT HAR HNC MDT @@ -16,13 +23,13 @@ +0100 A CET DFT WAT WEDT WEST +0200 B CAT CEDT CEST EET SAST WAST +0300 C EAT EEDT EEST IDT MSK -+0400 D AMT AZT GET GST KUYT MSD MUT RET SAMT SCT ++0400 D AMT AZT GET KUYT MSD MUT RET SAMT SCT +0500 E AMST AQTT AZST HMT MAWT MVT PKT TFT TJT TMT UZT YEKT +0600 F ALMT BIOT BTT IOT KGT NOVT OMST YEKST +0700 G CXT DAVT HOVT ICT KRAT NOVST OMSST THA WIB +0800 H ACT AWST BDT BNT CAST HKT IRKT KRAST MYT PHT SGT ULAT WITA WST +0900 I AWDT IRKST JST KST PWT TLT WDT WIT YAKT -+1000 K AEST ChST PGT VLAT YAKST YAPT ++1000 K AEST ChST GST PGT VLAT YAKST YAPT +1100 L AEDT LHDT MAGT NCT PONT SBT VLAST VUT +1200 M ANAST ANAT FJT GILT MAGST MHT NZST PETST PETT TVT WFT +1330 FJST NZDT diff --git a/tests/utils_test.py b/tests/utils_test.py index 89c7d015f..fc1745e4e 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -434,6 +434,27 @@ def test_legacy_wqp_triplet_resolves_to_utc(self): "2024-01-09 18:00:00", tz="UTC" ) + @pytest.mark.parametrize( + ("zone", "utc"), + [ + # Guam Standard Time, UTC+10, in both the USGS time-zone codes and + # the WQX TimeZone domain -- not Gulf Standard Time (UTC+4). + ("GST", "2024-06-01 00:00:00"), + # Hawaii-Aleutian Daylight Time, UTC-9, from the USGS codes. + ("HDT", "2024-06-01 19:00:00"), + ], + ) + def test_zone_resolves_as_the_services_define_it(self, zone, utc): + df = pd.DataFrame( + { + "Activity_StartDate": ["2024-06-01"], + "Activity_StartTime": ["10:00:00"], + "Activity_StartTimeZone": [zone], + } + ) + df = _wqx._attach_datetime_columns(df) + assert df["Activity_StartDateTime"][0] == pd.Timestamp(utc, tz="UTC") + def test_unknown_timezone_is_NaT(self): df = pd.DataFrame( { From c74dd739f005e95932829e9a188e65e31e311b01 Mon Sep 17 00:00:00 2001 From: thodson-usgs Date: Fri, 16 Oct 2026 09:17:50 -0500 Subject: [PATCH 2/2] docs(codes): scope the time-zone docstring to what the table follows --- dataretrieval/codes/timezones.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dataretrieval/codes/timezones.py b/dataretrieval/codes/timezones.py index 004ba5114..3a7e02aaa 100644 --- a/dataretrieval/codes/timezones.py +++ b/dataretrieval/codes/timezones.py @@ -1,10 +1,12 @@ """Time zone information. Maps the time-zone abbreviations that services put beside a local date and -time to UTC offsets. Several abbreviations name more than one zone worldwide; -where they do, the entry follows the services' own code lists (the USGS -time-zone codes and the WQX TimeZone domain), so ``GST`` is Guam Standard -Time rather than Gulf Standard Time. +time to UTC offsets. Several abbreviations name more than one zone worldwide. +``GST`` follows the USGS time-zone codes and the WQX TimeZone domain, which +both define it as Guam Standard Time (UTC+10), not Gulf Standard Time. Other +entries that differ from the USGS list (``CCT``, ``EAST``, ``NFT``, ``NZDT``, +``SST``, ``WAT``) have not been reconciled, and the two lists disagree with +each other on ``SST``. """ tz_str = """-1200 Y