-
Notifications
You must be signed in to change notification settings - Fork 214
fix(CORE-355): handle abbreviated timezone offsets in convert_partial_iso_format_to_full_iso_format #2116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(CORE-355): handle abbreviated timezone offsets in convert_partial_iso_format_to_full_iso_format #2116
Changes from 1 commit
d86d3fe
b38a4b5
c1dbe64
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import re | ||
| from datetime import datetime, timedelta, timezone | ||
| from typing import Optional | ||
|
|
||
|
|
@@ -89,17 +90,24 @@ def datetime_strftime(datetime: datetime, include_timezone: bool = False) -> str | |
| ) | ||
|
|
||
|
|
||
| _ABBREVIATED_TZ_OFFSET_PATTERN = re.compile(r"([+-])(\d{2})$") | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch — the original I've tightened the pattern to |
||
|
|
||
|
|
||
| def _normalize_timezone_offset(time_string: str) -> str: | ||
| return _ABBREVIATED_TZ_OFFSET_PATTERN.sub(r"\1\2:00", time_string) | ||
|
|
||
|
|
||
| def convert_partial_iso_format_to_full_iso_format(partial_iso_format_time: str) -> str: | ||
|
haritamar marked this conversation as resolved.
|
||
| try: | ||
| date = datetime.fromisoformat(partial_iso_format_time) | ||
| # Get the given date timezone | ||
| normalized = _normalize_timezone_offset(partial_iso_format_time) | ||
| date = datetime.fromisoformat(normalized) | ||
| time_zone_name = date.strftime("%Z") | ||
| time_zone = tz.gettz(time_zone_name) if time_zone_name else tz.UTC | ||
| date_with_timezone = date.replace(tzinfo=time_zone, microsecond=0) | ||
| return date_with_timezone.isoformat() | ||
| except ValueError: | ||
| logger.exception( | ||
| f'Failed to covert time string: "{partial_iso_format_time}" to ISO format' | ||
| f'Failed to convert time string: "{partial_iso_format_time}" to ISO format' | ||
| ) | ||
| return partial_iso_format_time | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Regex falsely matches date components (e.g.,
-15in2024-01-15) as abbreviated timezone offsetsThe regex
([+-])(\d{2})$is too broad and matches trailing-DDin date-only ISO strings, corrupting them before parsing.Root Cause and Impact
The pattern
_ABBREVIATED_TZ_OFFSET_PATTERN = re.compile(r"([+-])(\d{2})$")matches any string ending with+XXor-XX. This means a date-only string like"2024-01-15"matches on"-15"and gets rewritten to"2024-01-15:00".Verified with the actual code:
In the current Python 3.10 environment,
datetime.fromisoformat("2024-01-15:00")happens to parse identically todatetime.fromisoformat("2024-01-15")(both yield2024-01-15 00:00:00) becausefromisoformataccepts any single character as a date-time separator. So the output is currently identical by coincidence, but this is fragile — it relies on a quirk offromisoformat's separator handling.A safer pattern would anchor to a time component before the offset, e.g.:
or at minimum require a
Tor digit before the+/-:Impact: Currently minimal because the coincidental parse behavior produces the same result, but the function silently corrupts its input for date-only strings. This could become a real issue with future Python version changes to
fromisoformatparsing behavior, or with other partial ISO format inputs (like"2024-12").Was this helpful? React with 👍 or 👎 to provide feedback.