datetime.utcnow() is now deprecated

Python’s decision to deprecate `datetime.utcnow()` has reignited long‑running tensions over how programming languages should represent time, time zones, and “naive” vs. “aware” datetimes. Commenters debate whether all timestamps should always carry explicit UTC or zone information, how to model local vs. global events (like store hours or calendar appointments), and whether the change is worth the backward-compatibility and migration pain for large codebases, especially in finance. Many agree that Python’s datetime API has been error‑prone for years, but they diverge sharply on whether deprecation and eventual removal is a necessary fix or an unnecessary breaking change.

Naive vs timezone‑aware datetimes

  • Many agree Python’s “naive” vs “aware” split is error‑prone, especially when mixing them silently.
  • Core complaint: utcnow() sounds like it returns a UTC‑aware datetime but actually returns naive local‑semantics data; this has caused subtle bugs.
  • Some argue conceptually “all real datetimes have a timezone” and naive datetimes should be rare or clearly separate types.
  • Others insist naive UTC is a valid, efficient internal convention, widely used (e.g., in finance) and deprecating it is disruptive.

Use cases where local / naive times are needed

  • Recurring or local events: alarms at “8am local”, future appointments at “10am in Europe/London”, store opening hours “9:30am local”, recurring meetings, stock‑exchange open times.
  • These don’t map cleanly to a single UTC instant, especially when governments change DST rules or offsets after scheduling.
  • Some want distinct types: timestamps/instants vs local date/time vs recurring rules, to prevent misuse.

Storing and exchanging time

  • Strong support for “store past events in UTC, convert at display”; disagreement about future events.
  • Disagreement over best storage:
    • Epoch integers: simple and fast, but need implicit knowledge of epoch, units, and UTC; ambiguous without metadata.
    • ISO‑8601 strings: self‑describing and human‑readable, but slower and heavier.
    • DB types: warnings that “TIMESTAMP WITH TIME ZONE” in some DBs only stores UTC and discards the original zone; others argue it’s still useful.

DST, offsets, and weird timezones

  • Participants list tricky realities: half‑hour and 45‑minute offsets, historical odd offsets, frequent political changes, DST shifts, duplicated hours.
  • Point made that UTC↔local conversion is not a stable pure function over future dates; you need zone names and up‑to‑date tz databases.

What to use instead of utcnow & API design

  • Recommended pattern: datetime.now(timezone.utc) (or equivalent), possibly stripping tzinfo only at serialization boundaries.
  • Some wish Python had separate types for zoned vs zoneless datetimes (like Java, Rust, Elixir) and had made “aware” the default from the start.
  • Others argue Python already has dynamic features and mocking, so heavyweight abstractions (like .NET’s time provider) are overkill.

Backward compatibility and ecosystem impact

  • Concerns that deprecation will hit large legacy and financial codebases that standardized on naive UTC.
  • Counterpoint: deprecation first, removal later is safer than silently changing semantics; static and runtime analysis can find call sites.
  • Broader debate about Python’s willingness to break APIs in 3.x vs never‑break cultures (C, Java), and whether piecemeal changes are better than “Python 4”‑style big breaks.