Miscellaneous

This section contains API documentation for miscellaneous functions and data

Context managers

class whenever.patch_current_time(
dt: Instant | ZonedDateTime | OffsetDateTime,
/,
*,
keep_ticking: bool,
)[source]

Patch the current time to a fixed value (for testing purposes). Behaves as a context manager or decorator, with similar semantics to unittest.mock.patch.

Important

  • This function should be used only for testing purposes. It is not thread-safe or part of the stable API.

  • This function only affects whenever’s now functions. It does not affect the standard library’s time functions or any other libraries. Use the time_machine package if you also want to patch other libraries.

  • It doesn’t affect the system timezone. If you need to patch the system timezone, set the TZ environment variable in combination with reset_system_tz().

Example

>>> from whenever import Instant, patch_current_time
>>> i = Instant.from_utc(1980, 3, 2, hour=2)
>>> with patch_current_time(i, keep_ticking=False) as p:
...     assert Instant.now() == i
...     p.shift(hours=4)
...     assert i.now() == i.add(hours=4)
...
>>> assert Instant.now() != i
...
>>> @patch_current_time(i, keep_ticking=True)
... def test_thing(p):
...     assert (Instant.now() - i) < seconds(1)
...     p.shift(hours=8)
...     sleep(0.000001)
...     assert hours(8) < (Instant.now() - i) < hours(8.1)
class whenever.ignore_timezone_unaware_arithmetic_warning[source]

Context manager to suppress TimeZoneUnawareArithmeticWarning.

This warning is always emitted when performing arithmetic with exact time units on a PlainDateTime, or when measuring the difference between two PlainDateTime values. Use this context manager if you: (a) explicitly accept potentially incorrect results, (b) know no timezone transitions occur in the interval, or (c) are working with clock times not representing a real-world timezone.

Example

>>> from whenever import PlainDateTime, TimeDelta
>>> dt = PlainDateTime(2023, 3, 23, hour=12)
>>> with ignore_timezone_unaware_arithmetic_warning():
...     dt.add(hours=2)  # no warning
PlainDateTime("2023-03-23 14:00:00")
class whenever.ignore_days_not_always_24h_warning[source]

Context manager to ignore warnings about days that are not always 24 hours long (due to DST transitions).

Example

>>> from whenever import TimeDelta
>>> d = TimeDelta(hours=100)
>>> with ignore_days_not_always_24h_warning():
...     d.total("days")  # no warning
class whenever.ignore_potentially_stale_offset_warning[source]

Context manager to suppress PotentiallyStaleOffsetWarning.

This warning is emitted when operations on an OffsetDateTime may produce an incorrect UTC offset (e.g. shifting, rounding, replacing fields, or constructing from the current time or a UNIX timestamp). Use this context manager when the fixed offset is intentional and correct.

Example

>>> from whenever import OffsetDateTime, TimeDelta
>>> dt = OffsetDateTime(2023, 3, 23, offset=+1)
>>> with ignore_potentially_stale_offset_warning():
...     dt + TimeDelta(hours=1_000)  # no warning

Timezone data

whenever.TZPATH: tuple[str, ...]

The paths in which whenever will search for timezone data. By default, this is determined the same way as zoneinfo.TZPATH, although you can override it using reset_tzpath() for whenever specifically.

whenever.clear_tzcache(*, only_keys: Iterable[str] | None = None) None[source]

Clear the timezone cache. If only_keys is provided, only the cache for those keys will be cleared.

Caution

Calling this function may change the behavior of existing ZonedDateTime instances in surprising ways. Most significantly, exact_eq() may return False between two timezone instances with the same TZ ID, if this timezone definition was changed on disk.

Use this function only if you know that you need to.

Behaves similarly to zoneinfo.ZoneInfo.clear_cache().

whenever.reset_tzpath(target: Iterable[str | PathLike[str]] | None = None, /) None[source]

Reset or set the paths in which whenever will search for timezone data.

It does not affect the zoneinfo module or other libraries.

Note

Due to caching, you may find that looking up a timezone after setting the tzpath doesn’t load the timezone data from the new path. You may need to call clear_tzcache() if you want to force loading all timezones from the new path. Note that clearing the cache may have unexpected side effects, however.

Behaves similarly to zoneinfo.reset_tzpath()

whenever.available_timezones() set[str][source]

Gather the set of all available timezones.

Each call to this function will recalculate the available timezone names depending on the currently configured TZPATH, and the presence of the tzdata package.

Warning

This function may open a large number of files, since the first few bytes of timezone files must be read to determine if they are valid.

Note

This function behaves similarly to zoneinfo.available_timezones(), which means it ignores the “special” zones (e.g. posixrules, right/posix, etc.)

It should give the same result as zoneinfo.available_timezones(), unless whenever was configured to use a different tzpath using reset_tzpath().

whenever.reset_system_tz() None[source]

Resets the cached system timezone to the currently set system timezone.

>>> os.environ["TZ"] = "America/New_York"
>>> reset_system_tz()  # system tz is now New York
>>> os.environ["TZ"] = "Europe/London"
>>> ZonedDateTime.now_in_system_tz()  # still uses cached New York tz
ZonedDateTime(2025-06-18 15:11:08-04:00[America/New_York])
>>> reset_system_tz()  # system tz is now London
>>> ZonedDateTime.now_in_system_tz()
ZonedDateTime(2025-06-18 20:11:08+01:00[Europe/London])