Skip to content

fix: correctly handle negative UTC offsets in isoformat - #137

Open
binggao1230 wants to merge 1 commit into
ni:masterfrom
binggao1230:fix-52-isoformat-negative-tz
Open

fix: correctly handle negative UTC offsets in isoformat#137
binggao1230 wants to merge 1 commit into
ni:masterfrom
binggao1230:fix-52-isoformat-negative-tz

Conversation

@binggao1230

@binggao1230 binggao1230 commented Jun 24, 2026

Copy link
Copy Markdown

What does this Pull Request accomplish?

Fixes #52.

hightime.datetime.isoformat() built its result by splitting the base datetime.isoformat() string on "+" to separate the UTC offset, then re-joining with "+". Negative offsets use "-", so the split found nothing and the high-precision fractional seconds were appended after the offset instead of after the seconds:

>>> ht.datetime(2025, 1, 1, yoctosecond=40, tzinfo=dt.timezone(dt.timedelta(hours=-1))).isoformat()
'2025-01-01T00:00:00-01:00.000000000000000000000040'

This replaces the split with a regex match for the offset suffix ([+-]HH:MM or [+-]HH:MM:SS) at the end of the string, so the fractional part is inserted after the seconds and the offset is re-attached last. It also removes the xfail from the existing negative-offset case in tests/test_datetime.py, which now passes.

Why should this Pull Request be merged?

The output was not a valid ISO 8601 string and could not be parsed back, for any sub-microsecond datetime west of UTC. Positive offsets and naive datetimes were unaffected, which is why it went unnoticed. The repository already had a test for the case, marked xfail against #52.

What testing has been done?

  • python -m pytest tests/test_datetime.py -k isoformat — 12 passed; the negative-offset case fails on master with the xfail removed, confirming the test covers the fix
  • python -m pytest tests/ — 408 passed
  • ni-python-styleguide lint — clean
  • mypy — Success: no issues found in 8 source files
  • CI on this PR: 29/29 checks passing

When a datetime with sub-microsecond precision (femtoseconds or
yoctoseconds) had a negative UTC offset (e.g. -01:00), isoformat()
placed the offset in the middle of the fractional-seconds string instead
of appending it at the end.

The old code split the base isoformat string on "+" to separate the UTC
offset, so negative offsets (which use "-") were never detected and the
offset ended up embedded inside the result:

  '2025-01-01T00:00:00-01:00.000000000000000000000040'

Fix: use a regex to find the UTC offset suffix ([+-]HH:MM or
[+-]HH:MM:SS) at the end of the string before inserting the
high-precision fractional part.

Fixes ni#52.
@bkeryan

bkeryan commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

@gaoflow, thank you for contributing.

Please use the project's pull request template, like you did in #136

@binggao1230

Copy link
Copy Markdown
Author

Sorry about that — description rewritten using the template, same as #136. Rechecked on current master while I was in there: 408 tests pass, lint and mypy clean, 29/29 CI green.

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.

isoformat handles negative timezone offset incorrectly

2 participants