Skip to main content

_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​

LinesSymbolPurpose
1-60module header, MINYEAR/MAXYEARConstants: year range 1-9999, epoch helpers
61-200_check_* helpersArgument validation (year, month, day, hour, ...)
201-400timedeltaStores days, seconds, microseconds after normalization
401-420timedelta._getstate / __reduce__Pickle protocol
421-700dateProleptic Gregorian calendar arithmetic
701-900tzinfo / timezoneAbstract base plus fixed-offset concrete class
901-1400timeWall-clock time with optional tzinfo
1401-2200datetimeCombines date + time; heaviest class
2201-2400datetime.fromisoformatFast path parser for ISO 8601 strings
2401-2700strptime bridge, _wrap_strftimeFormat 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

):

  1. Converts every unit to a (days, seconds, microseconds) triple.
  2. Carries microseconds into seconds when abs(us) >= 1_000_000.
  3. Carries seconds into days when abs(s) >= 86_400.
  4. Raises OverflowError if 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

):

  • utcoffset must return a timedelta with magnitude less than one day, or None.
  • dst same contract; used only for display and fold arithmetic.
  • tzname must return a str or None.

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

) avoids strptime 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​

  • timedelta normalization is purely integer arithmetic and ports cleanly to Go with int64 fields.
  • The tzinfo protocol maps naturally to a Go interface with UTCOffset, DST, and TZName methods.
  • fromisoformat fast path avoids importing re; the Go port can skip the regex engine entirely for the common case.
  • MINYEAR/MAXYEAR are module-level constants; expose them via objects.DatetimeModule attributes.
  • 3.14 adds datetime.strptime cache invalidation when the locale changes (bpo-28638 follow-up). The gopy port should track locale state in the same way.