_pydatetime.py annotation
CPython ships two implementations of the datetime module: a C accelerator (Modules/_datetimemodule.c) and this pure-Python fallback. The fallback is the authoritative readable reference. The C module replicates it exactly; when they diverge the C module is the bug.
Map
| Lines | Symbol | Purpose |
|---|---|---|
| 1-60 | module header, MINYEAR/MAXYEAR | Constants: year range 1-9999, epoch helpers |
| 61-200 | _check_* helpers | Argument validation (year, month, day, hour, ...) |
| 201-400 | timedelta | Stores days, seconds, microseconds after normalization |
| 401-420 | timedelta._getstate / __reduce__ | Pickle protocol |
| 421-700 | date | Proleptic Gregorian calendar arithmetic |
| 701-900 | tzinfo / timezone | Abstract base plus fixed-offset concrete class |
| 901-1400 | time | Wall-clock time with optional tzinfo |
| 1401-2200 | datetime | Combines date + time; heaviest class |
| 2201-2400 | datetime.fromisoformat | Fast path parser for ISO 8601 strings |
| 2401-2700 | strptime bridge, _wrap_strftime | Format string expansion and locale hooks |
Reading
timedelta normalization
timedelta.__new__ accepts keyword arguments in any combination of weeks, days, hours, minutes, seconds, milliseconds, and microseconds. All values are collapsed into three canonical fields. The normalization loop (
cpython 3.14 @ ab2d84fe1023/Lib/_pydatetime.py
):- Converts every unit to a
(days, seconds, microseconds)triple. - Carries microseconds into seconds when
abs(us) >= 1_000_000. - Carries seconds into days when
abs(s) >= 86_400. - Raises
OverflowErrorif days fall outside[-999999999, 999999999].
The result is always in canonical form: 0 <= microseconds < 1_000_000 and 0 <= seconds < 86_400.
utcoffset / dst / tzname protocol
Any class that subclasses tzinfo must implement these three methods. datetime calls each one defensively and validates the return type (
cpython 3.14 @ ab2d84fe1023/Lib/_pydatetime.py
):utcoffsetmust return atimedeltawith magnitude less than one day, orNone.dstsame contract; used only for display and fold arithmetic.tznamemust return astrorNone.
The _check_tzinfo_arg helper enforces these constraints at construction time so no runtime surprises occur during arithmetic.
datetime.fromisoformat fast path
Before 3.11, fromisoformat accepted only the exact format produced by isoformat(). Since 3.11 it covers the full ISO 8601 profile. The fast path in _parse_isoformat_datetime (
cpython 3.14 @ ab2d84fe1023/Lib/_pydatetime.py
) avoidsstrptime entirely by scanning fixed-width fields with integer slicing and checking separator characters directly. The slow path falls back to a regex for edge cases such as week dates.
gopy notes
timedeltanormalization is purely integer arithmetic and ports cleanly to Go withint64fields.- The
tzinfoprotocol maps naturally to a Go interface withUTCOffset,DST, andTZNamemethods. fromisoformatfast path avoids importingre; the Go port can skip the regex engine entirely for the common case.MINYEAR/MAXYEARare module-level constants; expose them viaobjects.DatetimeModuleattributes.- 3.14 adds
datetime.strptimecache invalidation when the locale changes (bpo-28638 follow-up). The gopy port should track locale state in the same way.