Skip to content

Fix strpfromiso silently corrupting non-UTC timestamps#562

Open
mittalpk wants to merge 1 commit into
process-intelligence-solutions:releasefrom
mittalpk:fix/strpfromiso-utc-offset-conversion
Open

Fix strpfromiso silently corrupting non-UTC timestamps#562
mittalpk wants to merge 1 commit into
process-intelligence-solutions:releasefrom
mittalpk:fix/strpfromiso-utc-offset-conversion

Conversation

@mittalpk

Copy link
Copy Markdown

Fixes #561

Summary

strpfromiso (the default ISO8601 date parser for Python >= 3.7) silently corrupts any timestamp that has a non-UTC offset, whenever ENABLE_DATETIME_COLUMNS_AWARE is enabled — which is the default for everyone except cuDF/RAPIDS installs.

fix_naivety() called dt.replace(tzinfo=timezone.utc) on an already-aware datetime. replace() only relabels the timezone; it does not convert the wall-clock value. A timestamp like 2026-07-23T10:00:00+05:00 (which is 05:00 UTC) was silently stored as 2026-07-23T10:00:00+00:00 — shifted by 5 hours, with no warning or error.

Fix

Only relabel (assume UTC) when the parsed value has no offset at all (nothing to convert from — same behavior as before for naive input). When it does have an offset, convert via astimezone(timezone.utc), matching the already-correct tz_convert("UTC") behavior in the sibling fix_dataframe_column() function a few lines above it in the same file.

Testing

Added tests/dt_parsing_test.py covering:

  • positive and negative non-UTC offsets (the bug case)
  • the existing Z-suffix path (still correct)
  • naive input with no offset at all (unchanged behavior — treated as already UTC, not reinterpreted through the host's local timezone)
  • the ENABLE_DATETIME_COLUMNS_AWARE = False branch (unchanged)

Verified the two offset-conversion tests fail against the pre-fix code and pass against the fix. Also ran the existing business_hours_test.py and xes_impexp_test.py/xes_deep_coverage_test.py suites (downstream consumers of this parser) — all pass, no regressions.

How did I verify: python -m pytest tests/dt_parsing_test.py tests/business_hours_test.py tests/xes_impexp_test.py tests/xes_deep_coverage_test.py -v from the tests/ directory, all green.

…-intelligence-solutions#561)

fix_naivety() used replace(tzinfo=timezone.utc) on already-aware
datetimes, which relabels the timezone without converting the
wall-clock value. A timestamp like 2026-07-23T10:00:00+05:00
(05:00 UTC) was silently stored as 2026-07-23T10:00:00+00:00,
shifted by the source offset.

Fix: only relabel (assume UTC) when the parsed value has no offset
at all; convert via astimezone() when it does, matching the
already-correct tz_convert("UTC") behavior in the sibling
fix_dataframe_column() function.

Adds regression tests covering positive/negative offsets, the
existing Z-suffix path, naive input, and the aware-disabled branch.

Signed-off-by: Praveen Mittal <pkmittal28@gmail.com>
@fit-alessandro-berti

Copy link
Copy Markdown
Contributor

Dear @mittalpk thank you for your report.

Could you start the contribution level agreement as in https://processintelligence.solutions/pm4py/contributing ?

@mittalpk

Copy link
Copy Markdown
Author

Thanks @fit-alessandro-berti
I just sent a review/CLA request to info@processintelligence.solutions referencing this PR.
Happy to provide anything else needed in the meantime.

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.

Bug: strpfromiso date parser silently corrupts non-UTC timestamps (replace() instead of astimezone())

2 participants