Skip to content

Commit 1201aef

Browse files
fix: zero-pad year in ISO 8601 datetime formatting
`_format_datetime_iso8601` used `strftime("%Y")` which produces fewer than 4 digits for years before 1000 on Linux/glibc. The resulting string (e.g., "1-01-01 00:00:00+00:00") cannot be parsed back by `fromisoformat()`, breaking roundtrip for pre-epoch dates. Use `f"{value.year:04d}"` for the year field to ensure 4-digit years per ISO 8601. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d48a734 commit 1201aef

2 files changed

Lines changed: 17 additions & 1 deletion

File tree

src/dqlitewire/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def decode_blob(data: bytes) -> tuple[bytes, int]:
149149

150150
def _format_datetime_iso8601(value: datetime.datetime) -> str:
151151
"""Format a datetime to ISO 8601 string matching Go's time format."""
152-
formatted = value.strftime("%Y-%m-%d %H:%M:%S")
152+
formatted = f"{value.year:04d}" + value.strftime("-%m-%d %H:%M:%S")
153153
if value.microsecond:
154154
formatted += f".{value.microsecond:06d}".rstrip("0")
155155
utcoffset = value.utcoffset()

tests/test_types.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,22 @@ def test_encode_decode_iso8601(self) -> None:
379379
assert decoded.minute == 30
380380
assert decoded.second == 45
381381

382+
def test_encode_decode_pre_epoch_datetime(self) -> None:
383+
"""Pre-epoch datetimes (year < 1000) must roundtrip correctly.
384+
strftime('%Y') produces fewer than 4 digits on some platforms,
385+
which breaks fromisoformat on decode.
386+
"""
387+
import datetime
388+
389+
dt = datetime.datetime(1, 1, 1, tzinfo=datetime.UTC)
390+
encoded, vtype = encode_value(dt)
391+
assert vtype == ValueType.ISO8601
392+
decoded, _ = decode_value(encoded, ValueType.ISO8601)
393+
assert isinstance(decoded, datetime.datetime)
394+
assert decoded.year == 1
395+
assert decoded.month == 1
396+
assert decoded.day == 1
397+
382398
def test_decode_iso8601_empty_string_returns_none(self) -> None:
383399
"""Empty ISO8601 string should decode as None, matching Go's nil."""
384400
encoded, _ = encode_value("", ValueType.ISO8601)

0 commit comments

Comments
 (0)