Skip to content

fix(timezone): Make datetime usage timezone-aware for DTZ lint rules - #8355

Merged
jenshnielsen merged 5 commits into
microsoft:mainfrom
jenshnielsen:ruff_016_timezone
Jul 31, 2026
Merged

fix(timezone): Make datetime usage timezone-aware for DTZ lint rules#8355
jenshnielsen merged 5 commits into
microsoft:mainfrom
jenshnielsen:ruff_016_timezone

Conversation

@jenshnielsen

Copy link
Copy Markdown
Collaborator
  • Use datetime.now(timezone.utc).astimezone() for local time with UTC offset
  • Update all datetime.fromtimestamp() calls with tz parameter
  • Store parameter cache timestamps as timezone-aware local time
  • Parameter snapshot 'ts' field now includes UTC offset (e.g. '2024-01-01 13:00:00+01:00')
  • Fix buggy manual timezone computation in AWG70000A driver
  • Update all test files to use timezone-aware datetimes
  • Update snapshot parsing to use fromisoformat() for ISO 8601 format

Fixes DTZ005, DTZ006, DTZ007 ruff lint violations. Existing datasets remain unaffected; only new ones have explicit timezone info.

- Use datetime.now(timezone.utc).astimezone() for local time with UTC offset
- Update all datetime.fromtimestamp() calls with tz parameter
- Store parameter cache timestamps as timezone-aware local time
- Parameter snapshot 'ts' field now includes UTC offset (e.g. '2024-01-01 13:00:00+01:00')
- Fix buggy manual timezone computation in AWG70000A driver
- Update all test files to use timezone-aware datetimes
- Update snapshot parsing to use fromisoformat() for ISO 8601 format

Fixes DTZ005, DTZ006, DTZ007 ruff lint violations.
Existing datasets remain unaffected; only new ones have explicit timezone info.
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.65217% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 71.09%. Comparing base (a997230) to head (e6ff912).

Files with missing lines Patch % Lines
...rc/qcodes/instrument_drivers/Keysight/Infiniium.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8355   +/-   ##
=======================================
  Coverage   71.09%   71.09%           
=======================================
  Files         305      305           
  Lines       31913    31903   -10     
=======================================
- Hits        22687    22681    -6     
+ Misses       9226     9222    -4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/qcodes/instrument_drivers/tektronix/AWG70000A.py
Comment thread tests/dataset/test_links.py
jenshnielsen and others added 3 commits July 31, 2026 12:44
Timestamps are stored in the QCoDeS database as POSIX timestamps, which do
not capture the timezone in which the measurement was performed. Rendering
them with `time.localtime` and a format without a UTC offset therefore
produced ambiguous strings, in particular once exported to NetCDF/xarray.

- `raw_time_to_str_time` now uses `datetime.fromtimestamp(ts, tz=UTC)`
  followed by `astimezone()` instead of `time.localtime`
- Default format of `raw_time_to_str_time`, `run_timestamp` and
  `completed_timestamp` changed to `%Y-%m-%d %H:%M:%S%z`
- Add tests covering the xarray/NetCDF export of these attributes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 82a9243d-3f0d-43fd-b3fb-861b37591755
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 82a9243d-3f0d-43fd-b3fb-861b37591755
`generate_log_file_name` and the Keysight Infiniium screenshot helper were
changed to `datetime.now(UTC)` while silencing the DTZ lint rules, which
switched their timestamps from local time to UTC. Use `.astimezone()` to
restore the previous local time behaviour.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 82a9243d-3f0d-43fd-b3fb-861b37591755
@jenshnielsen
jenshnielsen marked this pull request as ready for review July 31, 2026 12:07
@jenshnielsen
jenshnielsen requested a review from a team as a code owner July 31, 2026 12:07
@jenshnielsen
jenshnielsen requested a review from Copilot July 31, 2026 12:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request updates QCoDeS to use timezone-aware datetime values throughout the codebase to satisfy Ruff DTZ lint rules and to make newly produced timestamps unambiguous by including a UTC offset where appropriate (while continuing to store datasets as POSIX timestamps).

Changes:

  • Make parameter cache timestamps timezone-aware (local timezone) and serialize parameter snapshot "ts" using ISO 8601 (with UTC offset).
  • Change default dataset timestamp string formats (run_timestamp, completed_timestamp, raw_time_to_str_time) to include %z (UTC offset) and update parsing/export tests accordingly.
  • Fix manual timezone offset formatting in the Tektronix AWG70000A driver and update other timestamp producers (logger, widget, drivers) to use tz-aware datetimes.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/parameter/test_snapshot.py Update snapshot timestamp parsing to fromisoformat and use tz-aware now.
tests/parameter/test_parameter_cache.py Use tz-aware datetimes in cache timestamp assertions.
tests/parameter/test_group_parameter.py Use tz-aware datetimes in group parameter cache timestamp assertions.
tests/parameter/test_get_latest.py Use tz-aware datetimes in get_latest timestamp assertions.
tests/dataset/test_links.py Use tz-aware datetimes when generating synthetic timestamps.
tests/dataset/test_dataset_loading.py Parse default-formatted timestamps with %z using datetime.strptime.
tests/dataset/test_dataset_export.py Add coverage asserting exported timestamps include UTC offset and match raw instants.
src/qcodes/parameters/parameter_base.py Serialize snapshot "ts" with datetime.isoformat(..., timespec="seconds").
src/qcodes/parameters/cache.py Store cache timestamps as tz-aware local time; update expiration cutoff logic.
src/qcodes/logger/logger.py Generate log file date string from tz-aware local time.
src/qcodes/interactive_widget.py Compute elapsed time using UTC-aware fromtimestamp (DST-safe).
src/qcodes/instrument_drivers/tektronix/AWG70000A.py Fix timezone offset generation using tz-aware local time (DST-correct).
src/qcodes/instrument_drivers/Keysight/Infiniium.py Make screenshot filename timestamp tz-aware local time.
src/qcodes/dataset/sqlite/queries.py Render raw POSIX timestamps via tz-aware local time; default format includes %z.
src/qcodes/dataset/sqlite/db_overview.py Convert timestamps via fromtimestamp(..., tz=UTC).astimezone() before formatting.
src/qcodes/dataset/data_set_protocol.py Update default dataset timestamp formats to include %z and clarify docs.
pyproject.toml Stop ignoring DTZ rules now that code is updated.
docs/examples/DataSet/Linking to parent datasets.ipynb Use tz-aware datetime.now(datetime.UTC) in the example.
docs/changes/newsfragments/8345.improved_driver Document AWG70000A timezone-offset fix.
docs/changes/newsfragments/8345.breaking Document breaking changes in timestamp formatting and cache timestamp tz-awareness.
Suppressed comments (1)

src/qcodes/parameters/cache.py:206

  • oldest_accepted_timestamp is computed by subtracting a timedelta from a local-time (zoneinfo) datetime. Datetime arithmetic with local zoneinfo does not normalize offsets across DST transitions, so this can miscompute the cutoff instant around DST changes and lead to incorrect cache expiration decisions. Compute the cutoff in UTC and compare in UTC to make the age check timeline-correct.
        oldest_accepted_timestamp = datetime.now(UTC).astimezone() - timedelta(
            seconds=self._max_val_age
        )
        too_old = self._timestamp < oldest_accepted_timestamp
        return too_old

Comment thread pyproject.toml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jenshnielsen
jenshnielsen enabled auto-merge July 31, 2026 12:15
@jenshnielsen
jenshnielsen added this pull request to the merge queue Jul 31, 2026
Merged via the queue into microsoft:main with commit 355ba4b Jul 31, 2026
17 checks passed
@jenshnielsen
jenshnielsen deleted the ruff_016_timezone branch July 31, 2026 12:57
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.

3 participants