Exceptions and warnings¶
Warnings¶
- exception whenever.NaiveArithmeticWarning[source]¶
Bases:
PotentialDstBugWarningRaised when exact-time arithmetic is performed on a
PlainDateTimewithout timezone context.PlainDateTimecarries no timezone information, so it can’t account for DST transitions. When you add or subtract exact time units (hours, minutes, seconds) or measure the exact difference between twoPlainDateTimevalues, the computation treats every hour as equal. If a timezone transition falls in the interval, the result may be off by an hour or more.When it can occur
from whenever import PlainDateTime # On 2023-10-29, Amsterdam clocks fall back at 3:00 AM. # PlainDateTime has no knowledge of this. d = PlainDateTime(2023, 10, 29, 1, 30) d.add(hours=2) # NaiveArithmeticWarning # PlainDateTime("2023-10-29 03:30:00") # ^^ only 1 real hour passed in Amsterdam (clocks went back) # Also emitted for exact-unit differences: d2 = PlainDateTime(2023, 10, 30, 1, 30) d2 - d # NaiveArithmeticWarning
How to fix it
Attach a timezone with
assume_tz()first, then perform arithmetic on the resultingZonedDateTime:d.assume_tz("Europe/Amsterdam").add(hours=2) # ZonedDateTime("2023-10-29 02:30:00+01:00[Europe/Amsterdam]") ✓
To suppress when timezone context doesn’t apply (e.g. simulations, clock times not tied to a real-world timezone, or when you know no transitions occur in the interval), pass
naive_arithmetic_ok=True(or use Python’s standard warning filters):d.add(hours=2, naive_arithmetic_ok=True)
- exception whenever.DaysAssumed24HoursWarning[source]¶
Bases:
PotentialDstBugWarningRaised when days are treated as exactly 24 hours, which may be wrong across a DST transition.
TimeDeltaalways represents exact time. Constructing one withdaysorweekskwargs converts those units to nanoseconds using fixed 86400-second days. If you later add this delta to aZonedDateTimeon a day where clocks spring forward or fall back, the local time of the result will be off by the transition length (usually one hour).When it can occur
from whenever import TimeDelta, ZonedDateTime # TimeDelta(days=1) is exactly 86 400 seconds — no DST awareness. delta = TimeDelta(days=1) # DaysAssumed24HoursWarning # Adding it to a ZonedDateTime on a spring-forward day gives the # wrong local time: eve = ZonedDateTime(2025, 3, 30, 12, tz="Europe/Amsterdam") eve + delta # ZonedDateTime("2025-03-31 13:00:00+02:00[Europe/Amsterdam]") # ^^ 13:00, not 12:00 — one hour lost to the DST transition
How to fix it
Use calendar-based arithmetic directly on the datetime to preserve local time across transitions:
eve.add(days=1) # ZonedDateTime("2025-03-31 12:00:00+02:00[Europe/Amsterdam]") ✓
To suppress when exact 24-hour arithmetic is genuinely intended, pass
days_assumed_24h_ok=True(or use Python’s standard warning filters):TimeDelta(days=1, days_assumed_24h_ok=True)
- exception whenever.StaleOffsetWarning[source]¶
Bases:
PotentialDstBugWarningRaised when an
OffsetDateTimeoperation may silently preserve an incorrect UTC offset.A fixed UTC offset (e.g.
+02:00) carries no timezone rules — it doesn’t know about DST, historical offset changes, or future policy decisions. After shifting, rounding, or replacing fields of anOffsetDateTime, the original offset is kept verbatim. If the region’s rules changed since that offset was recorded, the result is a timestamp that is off by the difference — silently.When it can occur
from whenever import OffsetDateTime # Denver is UTC-7 in winter, UTC-6 in summer. # On 2024-03-10, clocks spring forward at 2:00 AM. d = OffsetDateTime(2024, 3, 9, 13, offset=-7) d.add(hours=24) # StaleOffsetWarning # OffsetDateTime("2024-03-10 13:00:00-07:00") # ^^ -07:00 is wrong; Denver is -06:00 on this date
How to fix it
Convert to
ZonedDateTimefirst so the offset updates automatically with the timezone rules:d.assume_tz("America/Denver").add(hours=24) # ZonedDateTime("2024-03-10 14:00:00-06:00[America/Denver]") ✓
To suppress when the fixed offset is deliberate and known to be correct, pass
stale_offset_ok=True(or use Python’s standard warning filters):d.add(hours=24, stale_offset_ok=True)
- exception whenever.PotentialDstBugWarning[source]¶
Bases:
UserWarningBase class for warnings about potential DST-related bugs in user code.
Not raised directly. Subclasses cover three distinct scenarios:
DaysAssumed24HoursWarning— days treated as exact 24-hour unitsStaleOffsetWarning— fixed offset may be wrong after a DST shiftNaiveArithmeticWarning— exact-time arithmetic without timezone context
Catching or filtering this base class handles all three at once:
import warnings, whenever warnings.filterwarnings("error", category=whenever.PotentialDstBugWarning)
- exception whenever.WheneverDeprecationWarning[source]¶
Bases:
UserWarningRaised when a deprecated feature of the
wheneverlibrary is used.This is a custom warning class (not a subclass of
DeprecationWarning) so that deprecation warnings from this library are visible by default—unlike standardDeprecationWarning, which Python silences in production code.
Exceptions¶
- exception whenever.RepeatedTime[source]¶
Bases:
ValueErrorA datetime is repeated in a timezone, e.g. because of DST
- exception whenever.SkippedTime[source]¶
Bases:
ValueErrorA datetime is skipped in a timezone, e.g. because of DST
- exception whenever.InvalidOffsetError[source]¶
Bases:
ValueErrorA string has an invalid offset for the given zone
- exception whenever.TimeZoneNotFoundError[source]¶
Bases:
ValueErrorA timezone with the given ID was not found