ISO 8601 timestamps emitted with different precision in Python vs Node
Severity: Medium
Affected repos: middleware-python, middleware-node, api
Component boundary: middleware → API telemetry
Symptom
- Python emits
datetime.now(timezone.utc).isoformat() → microsecond precision with +00:00 suffix: "2026-05-13T14:30:45.123456+00:00".
- Node emits
new Date().toISOString() → millisecond precision with Z suffix: "2026-05-13T14:30:45.123Z".
The API stores windowStart and windowEnd and later compares across SDKs in rollups. Sorting and grouping still work (ISO 8601 collation), but anyone who joins on equality, parses with a fixed format, or computes deltas across SDKs has to handle the shape difference.
Evidence
middleware-python/recost/_aggregator.py — datetime.now(timezone.utc).isoformat().
middleware-node/src/core/aggregator.ts — new Date().toISOString().
Impact
- Inconsistent wire format. Cosmetic in most analyses; potentially a sharp edge in any future code that does exact-string compare or parses with a tighter format.
Fix recommendation
Normalize both to millisecond-precision Z format (matches Node, which is more compact):
# Python
def _iso_now() -> str:
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace("+00:00", "Z")
Verification
- Python and Node SDKs emit identical timestamp string formats for the same instant (within ms).
Related
Parity with recost-dev/middleware-node#20. Python is the side that should change to match Node's millisecond-Z format.
ISO 8601 timestamps emitted with different precision in Python vs Node
Severity: Medium
Affected repos:
middleware-python,middleware-node,apiComponent boundary: middleware → API telemetry
Symptom
datetime.now(timezone.utc).isoformat()→ microsecond precision with+00:00suffix:"2026-05-13T14:30:45.123456+00:00".new Date().toISOString()→ millisecond precision withZsuffix:"2026-05-13T14:30:45.123Z".The API stores
windowStartandwindowEndand later compares across SDKs in rollups. Sorting and grouping still work (ISO 8601 collation), but anyone who joins on equality, parses with a fixed format, or computes deltas across SDKs has to handle the shape difference.Evidence
middleware-python/recost/_aggregator.py—datetime.now(timezone.utc).isoformat().middleware-node/src/core/aggregator.ts—new Date().toISOString().Impact
Fix recommendation
Normalize both to millisecond-precision
Zformat (matches Node, which is more compact):Verification
Related
Parity with recost-dev/middleware-node#20. Python is the side that should change to match Node's millisecond-Z format.