fix(timezone): Make datetime usage timezone-aware for DTZ lint rules - #8355
Merged
Conversation
- 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 Report❌ Patch coverage is
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. 🚀 New features to boost your workflow:
|
jenshnielsen
commented
Jul 31, 2026
jenshnielsen
commented
Jul 31, 2026
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
astafan8
approved these changes
Jul 31, 2026
Contributor
There was a problem hiding this comment.
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_timestampis computed by subtracting atimedeltafrom 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
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes DTZ005, DTZ006, DTZ007 ruff lint violations. Existing datasets remain unaffected; only new ones have explicit timezone info.