πŸ“– API referenceΒΆ

All classes are immutable.

DatetimesΒΆ

Common behaviorΒΆ

The following base classes encapsulate common behavior. They are not meant to be used directly.

class whenever._BasicConversions[source]ΒΆ

Methods for types converting to/from the standard library and ISO8601:

(This base class class itself is not for public use.)

abstract classmethod from_py_datetime(d: datetime, /) _T[source]ΒΆ

Create an instance from a datetime object. Inverse of py_datetime().

Note

The datetime is checked for validity, raising similar exceptions to the constructor. ValueError is raised if the datetime doesn’t have the correct tzinfo matching the class. For example, ZonedDateTime requires a ZoneInfo tzinfo.

Warning

No exceptions are raised if the datetime is ambiguous. Its fold attribute is used to disambiguate.

py_datetime() datetime[source]ΒΆ

Convert to a standard library datetime

Note

Nanoseconds are truncated to microseconds. If you wish to customize the rounding behavior, use the round() method first.

abstract format_common_iso() str[source]ΒΆ

Format as common ISO string representation. Each subclass has a different format.

See here for more information.

abstract classmethod parse_common_iso(s: str, /) _T[source]ΒΆ

Create an instance from common ISO 8601 representation, which is different for each subclass.

See here for more information.

class whenever._KnowsInstantΒΆ

Bases: _BasicConversions

Methods for types that represent a specific moment in time.

Implemented by:

(This base class class itself is not for public use.)

__eq__(other: object) bool[source]ΒΆ

Check if two datetimes represent at the same moment in time

a == b is equivalent to a.instant() == b.instant()

Note

If you want to exactly compare the values on their values instead, use exact_eq().

Example

>>> Instant.from_utc(2020, 8, 15, hour=23) == Instant.from_utc(2020, 8, 15, hour=23)
True
>>> OffsetDateTime(2020, 8, 15, hour=23, offset=1) == (
...     ZonedDateTime(2020, 8, 15, hour=18, tz="America/New_York")
... )
True
__ge__(other: _KnowsInstant) bool[source]ΒΆ

Compare two datetimes by when they occur in time

a >= b is equivalent to a.instant() >= b.instant()

Example

>>> OffsetDateTime(2020, 8, 15, hour=19, offset=-8) >= (
...     ZoneDateTime(2020, 8, 15, hour=20, tz="Europe/Amsterdam")
... )
True
__gt__(other: _KnowsInstant) bool[source]ΒΆ

Compare two datetimes by when they occur in time

a > b is equivalent to a.instant() > b.instant()

Example

>>> OffsetDateTime(2020, 8, 15, hour=19, offset=-8) > (
...     ZoneDateTime(2020, 8, 15, hour=20, tz="Europe/Amsterdam")
... )
True
__le__(other: _KnowsInstant) bool[source]ΒΆ

Compare two datetimes by when they occur in time

a <= b is equivalent to a.instant() <= b.instant()

Example

>>> OffsetDateTime(2020, 8, 15, hour=23, offset=8) <= (
...     ZoneDateTime(2020, 8, 15, hour=20, tz="Europe/Amsterdam")
... )
True
__lt__(other: _KnowsInstant) bool[source]ΒΆ

Compare two datetimes by when they occur in time

a < b is equivalent to a.instant() < b.instant()

Example

>>> OffsetDateTime(2020, 8, 15, hour=23, offset=8) < (
...     ZoneDateTime(2020, 8, 15, hour=20, tz="Europe/Amsterdam")
... )
True
abstract __sub__(other: _KnowsInstant) TimeDelta[source]ΒΆ

Calculate the duration between two datetimes

a - b is equivalent to a.instant() - b.instant()

Equivalent to difference().

See the docs on arithmetic for more information.

Example

>>> d = Instant.from_utc(2020, 8, 15, hour=23)
>>> d - ZonedDateTime(2020, 8, 15, hour=20, tz="Europe/Amsterdam")
TimeDelta(05:00:00)
difference(other: Instant | OffsetDateTime | ZonedDateTime | SystemDateTime, /) TimeDelta[source]ΒΆ

Calculate the difference between two instants in time.

Equivalent to __sub__().

See the docs on arithmetic for more information.

exact_eq(other: _T, /) bool[source]ΒΆ

Compare objects by their values (instead of whether they represent the same instant). Different types are never equal.

Note

If a.exact_eq(b) is true, then a == b is also true, but the converse is not necessarily true.

Examples

>>> a = OffsetDateTime(2020, 8, 15, hour=12, offset=1)
>>> b = OffsetDateTime(2020, 8, 15, hour=13, offset=2)
>>> a == b
True  # equivalent instants
>>> a.exact_eq(b)
False  # different values (hour and offset)
>>> a.exact_eq(Instant.now())
TypeError  # different types
classmethod from_timestamp(i: int | float, /, **kwargs) _T[source]ΒΆ

Create an instance from a UNIX timestamp. The inverse of timestamp().

ZonedDateTime and OffsetDateTime require a tz= and offset= kwarg, respectively.

Note

from_timestamp() also accepts floats, in order to ease migration from the standard library. Note however that timestamp() only returns integers. The reason is that floating point timestamps are not precise enough to represent all instants to nanosecond precision.

Example

>>> Instant.from_timestamp(0)
Instant(1970-01-01T00:00:00Z)
>>> ZonedDateTime.from_timestamp(1_123_000_000, tz="America/New_York")
ZonedDateTime(2005-08-02 12:26:40-04:00[America/New_York])
classmethod from_timestamp_millis(i: int, /, **kwargs) _T[source]ΒΆ

Like from_timestamp(), but for milliseconds.

classmethod from_timestamp_nanos(i: int, /, **kwargs) _T[source]ΒΆ

Like from_timestamp(), but for nanoseconds.

classmethod now(**kwargs) _T[source]ΒΆ

Create an instance from the current time.

This method on ZonedDateTime and OffsetDateTime requires a tz= and offset= kwarg, respectively.

Example

>>> Instant.now()
Instant(2021-08-15T22:12:00.49821Z)
>>> ZonedDateTime.now(tz="Europe/London")
ZonedDateTime(2021-08-15 23:12:00.50332+01:00[Europe/London])
timestamp() int[source]ΒΆ

The UNIX timestamp for this datetime. Inverse of from_timestamp().

Note

In contrast to the standard library, this method always returns an integer, not a float. This is because floating point timestamps are not precise enough to represent all instants to nanosecond precision. This decision is consistent with other modern date-time libraries.

Example

>>> Instant.from_utc(1970, 1, 1).timestamp()
0
>>> ts = 1_123_000_000
>>> Instant.from_timestamp(ts).timestamp() == ts
True
timestamp_millis() int[source]ΒΆ

Like timestamp(), but with millisecond precision.

timestamp_nanos() int[source]ΒΆ

Like timestamp(), but with nanosecond precision.

to_fixed_offset(offset: int | TimeDelta | None = None, /) OffsetDateTime[source]ΒΆ

Convert to an OffsetDateTime that represents the same moment in time.

If not offset is given, the offset is taken from the original datetime.

to_system_tz() SystemDateTime[source]ΒΆ

Convert to a SystemDateTime that represents the same moment in time.

to_tz(tz: str, /) ZonedDateTime[source]ΒΆ

Convert to a ZonedDateTime that represents the same moment in time.

Raises:

ZoneInfoNotFoundError – If the timezone ID is not found in the IANA database.

class whenever._KnowsLocalΒΆ

Bases: _BasicConversions, ABC

Methods for types that know a local date and time:

(The class itself is not for public use.)

abstract add(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0, hours: float = 0, minutes: float = 0, seconds: float = 0, milliseconds: float = 0, microseconds: float = 0, nanoseconds: int = 0, **kwargs) _T[source]ΒΆ

Add date and time units to this datetime.

Arithmetic on datetimes is complicated. Additional keyword arguments ignore_dst and disambiguate may be relevant for certain types and situations. See the docs on arithmetic for more information and the reasoning behind it.

date() Date[source]ΒΆ

The date part of the datetime

Example

>>> d = Instant.from_utc(2021, 1, 2, 3, 4, 5)
>>> d.date()
Date(2021-01-02)

To perform the inverse, use Date.at() and a method like assume_utc() or assume_tz():

>>> date.at(time).assume_tz("Europe/London")
property day: intΒΆ
property hour: intΒΆ
property minute: intΒΆ
property month: intΒΆ
property nanosecond: intΒΆ
abstract replace(**kwargs: Any) _T[source]ΒΆ

Construct a new instance with the given fields replaced.

Arguments are the same as the constructor, but only keyword arguments are allowed.

Note

If you need to shift the datetime by a duration, use the addition and subtraction operators instead. These account for daylight saving time and other complications.

Warning

The same exceptions as the constructor may be raised. For system and zoned datetimes, The disambiguate keyword argument is recommended to resolve ambiguities explicitly. For more information, see whenever.rtfd.io/en/latest/overview.html#ambiguity-in-timezones

Example

>>> d = LocalDateTime(2020, 8, 15, 23, 12)
>>> d.replace(year=2021)
LocalDateTime(2021-08-15 23:12:00)
>>>
>>> z = ZonedDateTime(2020, 8, 15, 23, 12, tz="Europe/London")
>>> z.replace(year=2021)
ZonedDateTime(2021-08-15T23:12:00+01:00)
replace_date(date: Date, /, **kwargs) _T[source]ΒΆ

Create a new instance with the date replaced

Example

>>> d = LocalDateTime(2020, 8, 15, hour=4)
>>> d.replace_date(Date(2021, 1, 1))
LocalDateTime(2021-01-01T04:00:00)
>>> zdt = ZonedDateTime.now("Europe/London")
>>> zdt.replace_date(Date(2021, 1, 1))
ZonedDateTime(2021-01-01T13:00:00.23439+00:00[Europe/London])

See replace() for more information.

replace_time(time: Time, /, **kwargs) _T[source]ΒΆ

Create a new instance with the time replaced

Example

>>> d = LocalDateTime(2020, 8, 15, hour=4)
>>> d.replace_time(Time(12, 30))
LocalDateTime(2020-08-15T12:30:00)
>>> zdt = ZonedDateTime.now("Europe/London")
>>> zdt.replace_time(Time(12, 30))
ZonedDateTime(2024-06-15T12:30:00+01:00[Europe/London])

See replace() for more information.

round(unit: Literal['day', 'hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'] = 'second', increment: int = 1, mode: Literal['ceil', 'floor', 'half_ceil', 'half_floor', 'half_even'] = 'half_even') _T[source]ΒΆ

Round the datetime to the specified unit and increment. Different rounding modes are available.

Examples

>>> d = ZonedDateTime(2020, 8, 15, 23, 24, 18, tz="Europe/Paris")
>>> d.round("day")
ZonedDateTime(2020-08-16 00:00:00+02:00[Europe/Paris])
>>> d.round("minute", increment=15, mode="floor")
ZonedDateTime(2020-08-15 23:15:00+02:00[Europe/Paris])

Notes

  • In the rare case that rounding results in an ambiguous time, the offset is preserved if possible. Otherwise, the time is resolved according to the β€œcompatible” strategy.

  • Rounding in β€œday” mode may be affected by DST transitions. i.e. on 23-hour days, 11:31 AM is rounded up.

  • For OffsetDateTime, the ignore_dst parameter is required, because it is possible (though unlikely) that the rounded datetime will not have the same offset.

  • This method has similar behavior to the round() method of Temporal objects in JavaScript.

property second: intΒΆ
abstract subtract(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0, hours: float = 0, minutes: float = 0, seconds: float = 0, milliseconds: float = 0, microseconds: float = 0, nanoseconds: int = 0, **kwargs) _T[source]ΒΆ

Inverse of add().

time() Time[source]ΒΆ

The time-of-day part of the datetime

Example

>>> d = ZonedDateTime(2021, 1, 2, 3, 4, 5, tz="Europe/Paris")
ZonedDateTime(2021-01-02T03:04:05+01:00[Europe/Paris])
>>> d.time()
Time(03:04:05)

To perform the inverse, use Time.on() and a method like assume_utc() or assume_tz():

>>> time.on(date).assume_tz("Europe/Paris")
property year: intΒΆ
class whenever._KnowsInstantAndLocalΒΆ

Bases: _KnowsLocal, _KnowsInstant

Common behavior for all types that know both a local time and an instant:

(The class itself it not for public use.)

instant() Instant[source]ΒΆ

Get the underlying instant in time

Example

>>> d = ZonedDateTime(2020, 8, 15, hour=23, tz="Europe/Amsterdam")
>>> d.instant()
Instant(2020-08-15 21:00:00Z)
local() LocalDateTime[source]ΒΆ

Get the underlying local date and time

As an inverse, LocalDateTime has methods assume_utc(), assume_fixed_offset() , assume_tz(), and assume_system_tz() which may require additional arguments.

property offset: TimeDeltaΒΆ

The UTC offset of the datetime

Concrete classesΒΆ

class whenever.InstantΒΆ

Bases: _KnowsInstant

Represents a moment in time with nanosecond precision.

This class is great for representing a specific point in time independent of location. It maps 1:1 to UTC or a UNIX timestamp.

Example

>>> from whenever import Instant
>>> py311_release = Instant.from_utc(2022, 10, 24, hour=17)
Instant(2022-10-24 17:00:00Z)
>>> py311_release.add(hours=3).timestamp()
1666641600
MIN: ClassVar[Instant] = Instant(0001-01-01 00:00:00Z)ΒΆ
MAX: ClassVar[Instant] = Instant(9999-12-31 23:59:59.999999999Z)ΒΆ
classmethod from_utc(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, *, nanosecond: int = 0) Instant[source]ΒΆ

Create an Instant defined by a UTC date and time.

format_rfc3339() str[source]ΒΆ

Format as an RFC 3339 string YYYY-MM-DD HH:MM:SSZ

If you prefer the T separator, use format_common_iso() instead.

The inverse of the parse_rfc3339() method.

Example

>>> Instant.from_utc(2020, 8, 15, hour=23, minute=12).format_rfc3339()
"2020-08-15 23:12:00Z"
classmethod parse_rfc3339(s: str, /) Instant[source]ΒΆ

Parse a UTC datetime in RFC 3339 format.

The inverse of the format_rfc3339() method.

Example

>>> Instant.parse_rfc3339("2020-08-15 23:12:00Z")
Instant(2020-08-15 23:12:00Z)
>>>
>>> # also valid:
>>> Instant.parse_rfc3339("2020-08-15T23:12:00+00:00")
>>> Instant.parse_rfc3339("2020-08-15_23:12:00.34Z")
>>> Instant.parse_rfc3339("2020-08-15t23:12:00z")
>>>
>>> # not valid (nonzero offset):
>>> Instant.parse_rfc3339("2020-08-15T23:12:00+02:00")

Important

Nonzero offsets will not be implicitly converted to UTC, but will raise a ValueError. Use OffsetDateTime.parse_rfc3339() if you’d like to parse an RFC 3339 string with a nonzero offset.

format_rfc2822() str[source]ΒΆ

Format as an RFC 2822 string.

The inverse of the parse_rfc2822() method.

Example

>>> Instant.from_utc(2020, 8, 15, hour=23, minute=12).format_rfc2822()
"Sat, 15 Aug 2020 23:12:00 GMT"
classmethod parse_rfc2822(s: str, /) Instant[source]ΒΆ

Parse a UTC datetime in RFC 2822 format.

The inverse of the format_rfc2822() method.

Example

>>> Instant.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 GMT")
Instant(2020-08-15 23:12:00Z)
>>> # also valid:
>>> Instant.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 +0000")
>>> Instant.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 -0000")
>>> Instant.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 UT")
>>> Instant.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 UTC")
>>> # Error: includes offset. Use OffsetDateTime.parse_rfc2822() instead
>>> Instant.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 +0200")

Important

  • This function parses, but does not validate the input (yet). This is due to the limitations of the underlying function email.utils.parsedate_to_datetime().

  • Nonzero offsets will not be implicitly converted to UTC. Use OffsetDateTime.parse_rfc2822() if you’d like to parse an RFC 2822 string with a nonzero offset.

add(*, hours: float = 0, minutes: float = 0, seconds: float = 0, milliseconds: float = 0, microseconds: float = 0, nanoseconds: int = 0) Instant[source]ΒΆ

Add a time amount to this instant.

See the docs on arithmetic for more information.

subtract(*, hours: float = 0, minutes: float = 0, seconds: float = 0, milliseconds: float = 0, microseconds: float = 0, nanoseconds: int = 0) Instant[source]ΒΆ

Subtract a time amount from this instant.

See the docs on arithmetic for more information.

round(unit: Literal['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'] = 'second', increment: int = 1, mode: Literal['ceil', 'floor', 'half_ceil', 'half_floor', 'half_even'] = 'half_even') Instant[source]ΒΆ

Round the instant to the specified unit and increment. Various rounding modes are available.

Examples

>>> Instant.from_utc(2020, 1, 1, 12, 39, 59).round("minute", 15)
Instant(2020-01-01 12:45:00Z)
>>> Instant.from_utc(2020, 1, 1, 8, 9, 13).round("second", 5, mode="floor")
Instant(2020-01-01 08:09:10Z)
__add__(delta: TimeDelta) Instant[source]ΒΆ

Add a time amount to this datetime.

See the docs on arithmetic for more information.

__sub__(other: TimeDelta | _KnowsInstant) Instant | TimeDelta[source]ΒΆ

Subtract another exact time or timedelta

Subtraction of deltas happens in the same way as the subtract() method. Subtraction of instants happens the same way as the difference() method.

See the docs on arithmetic for more information.

Example

>>> d = Instant.from_utc(2020, 8, 15, hour=23, minute=12)
>>> d - hours(24) - seconds(5)
Instant(2020-08-14 23:11:55Z)
>>> d - Instant.from_utc(2020, 8, 14)
TimeDelta(47:12:00)
class whenever.LocalDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, *, nanosecond: int = 0)ΒΆ

Bases: _KnowsLocal

A local date and time, i.e. it would appear to people on a wall clock.

It can’t be mixed with aware datetimes. Conversion to aware datetimes can only be done by explicitly assuming a timezone or offset.

Examples of when to use this type:

  • You need to express a date and time as it would be observed locally on the β€œwall clock” or calendar.

  • You receive a date and time without any timezone information, and you need a type to represent this lack of information.

  • In the rare case you truly don’t need to account for timezones, or Daylight Saving Time transitions. For example, when modeling time in a simulation game.

MIN: ClassVar[LocalDateTime] = LocalDateTime(0001-01-01 00:00:00)ΒΆ
MAX: ClassVar[LocalDateTime] = LocalDateTime(9999-12-31 23:59:59.999999999)ΒΆ
assume_utc() Instant[source]ΒΆ

Assume the datetime is in UTC, creating an Instant.

Example

>>> LocalDateTime(2020, 8, 15, 23, 12).assume_utc()
Instant(2020-08-15 23:12:00Z)
assume_fixed_offset(offset: int | TimeDelta, /) OffsetDateTime[source]ΒΆ

Assume the datetime has the given offset, creating an OffsetDateTime.

Example

>>> LocalDateTime(2020, 8, 15, 23, 12).assume_fixed_offset(+2)
OffsetDateTime(2020-08-15 23:12:00+02:00)
assume_tz(tz: str, /, disambiguate: Literal['compatible', 'earlier', 'later', 'raise'] = 'compatible') ZonedDateTime[source]ΒΆ

Assume the datetime is in the given timezone, creating a ZonedDateTime.

Note

The local datetime may be ambiguous in the given timezone (e.g. during a DST transition). Therefore, you must explicitly specify how to handle such a situation using the disambiguate argument. See the documentation for more information.

Example

>>> d = LocalDateTime(2020, 8, 15, 23, 12)
>>> d.assume_tz("Europe/Amsterdam", disambiguate="raise")
ZonedDateTime(2020-08-15 23:12:00+02:00[Europe/Amsterdam])
assume_system_tz(disambiguate: Literal['compatible', 'earlier', 'later', 'raise'] = 'compatible') SystemDateTime[source]ΒΆ

Assume the datetime is in the system timezone, creating a SystemDateTime.

Note

The local datetime may be ambiguous in the system timezone (e.g. during a DST transition). Therefore, you must explicitly specify how to handle such a situation using the disambiguate argument. See the documentation for more information.

Example

>>> d = LocalDateTime(2020, 8, 15, 23, 12)
>>> # assuming system timezone is America/New_York
>>> d.assume_system_tz(disambiguate="raise")
SystemDateTime(2020-08-15 23:12:00-04:00)
classmethod strptime(s: str, /, fmt: str) LocalDateTime[source]ΒΆ

Simple alias for LocalDateTime.from_py_datetime(datetime.strptime(s, fmt))

Example

>>> LocalDateTime.strptime("2020-08-15", "%Y-%m-%d")
LocalDateTime(2020-08-15 00:00:00)

Note

The parsed tzinfo must be be None. This means you CANNOT include the directives %z, %Z, or %:z in the format string.

difference(other: LocalDateTime, /, *, ignore_dst: bool = False) TimeDelta[source]ΒΆ

Calculate the difference between two local datetimes.

Important

The difference between two local datetimes implicitly ignores DST transitions and other timezone changes. To perform DST-safe operations, convert to a ZonedDateTime first. Or, if you don’t know the timezone and accept potentially incorrect results during DST transitions, pass ignore_dst=True. For more information, see the docs.

__eq__(other: object) bool[source]ΒΆ

Compare objects for equality. Only ever equal to other LocalDateTime instances with the same values.

Warning

To comply with the Python data model, this method can’t raise a TypeError when comparing with other types. Although it seems to be the sensible response, it would result in surprising behavior when using values as dictionary keys.

Use mypy’s --strict-equality flag to detect and prevent this.

Example

>>> LocalDateTime(2020, 8, 15, 23) == LocalDateTime(2020, 8, 15, 23)
True
>>> LocalDateTime(2020, 8, 15, 23, 1) == LocalDateTime(2020, 8, 15, 23)
False
>>> LocalDateTime(2020, 8, 15) == Instant.from_utc(2020, 8, 15)
False  # Use mypy's --strict-equality flag to detect this.
class whenever.OffsetDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, *, nanosecond: int = 0, offset: int | TimeDelta)ΒΆ

Bases: _KnowsInstantAndLocal

A datetime with a fixed UTC offset. Useful for representing the local time at a specific location.

Example

>>> # Midnight in Salt Lake City
>>> OffsetDateTime(2023, 4, 21, offset=-6)
OffsetDateTime(2023-04-21 00:00:00-06:00)

Note

Adjusting instances of this class do not account for daylight saving time. If you need to add or subtract durations from an offset datetime and account for DST, convert to a ZonedDateTime first, This class knows when the offset changes.

format_rfc3339() str[source]ΒΆ

Format as an RFC 3339 string YYYY-MM-DD HH:MM:SSΒ±HH:MM

If you prefer the T separator, use format_common_iso() instead.

The inverse of the parse_rfc3339() method.

Example

>>> OffsetDateTime(2020, 8, 15, hour=23, minute=12, offset=hours(4)).format_rfc3339()
"2020-08-15 23:12:00+04:00"

Note

The RFC3339 format does not allow for second-level precision of the UTC offset. This should not be a problem in practice, unless you’re dealing with pre-1950s timezones. The format_common_iso() does support this precision.

format_rfc2822() str[source]ΒΆ

Format as an RFC 2822 string.

The inverse of the parse_rfc2822() method.

Example

>>> OffsetDateTime(2020, 8, 15, 23, 12, offset=hours(2)).format_rfc2822()
"Sat, 15 Aug 2020 23:12:00 +0200"
classmethod parse_rfc3339(s: str, /) OffsetDateTime[source]ΒΆ

Parse a fixed-offset datetime in RFC 3339 format.

The inverse of the format_rfc3339() method.

Example

>>> OffsetDateTime.parse_rfc3339("2020-08-15 23:12:00+02:00")
OffsetDateTime(2020-08-15 23:12:00+02:00)
>>> # also valid:
>>> OffsetDateTime.parse_rfc3339("2020-08-15T23:12:00Z")
>>> OffsetDateTime.parse_rfc3339("2020-08-15_23:12:00.23-12:00")
>>> OffsetDateTime.parse_rfc3339("2020-08-15t23:12:00z")
classmethod parse_rfc2822(s: str, /) OffsetDateTime[source]ΒΆ

Parse an offset datetime in RFC 2822 format.

The inverse of the format_rfc2822() method.

Example

>>> OffsetDateTime.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 +0200")
OffsetDateTime(2020-08-15 23:12:00+02:00)
>>> # also valid:
>>> OffsetDateTime.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 UT")
>>> OffsetDateTime.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 GMT")
>>> OffsetDateTime.parse_rfc2822("Sat, 15 Aug 2020 23:12:00 MST")

Warning

  • This function parses, but does not validate the input (yet). This is due to the limitations of the underlying function email.utils.parsedate_to_datetime().

  • The offset -0000 has special meaning in RFC 2822, indicating a UTC time with unknown local offset. Thus, it cannot be parsed to an OffsetDateTime.

classmethod strptime(s: str, /, fmt: str) OffsetDateTime[source]ΒΆ

Simple alias for OffsetDateTime.from_py_datetime(datetime.strptime(s, fmt))

Example

>>> OffsetDateTime.strptime("2020-08-15+0200", "%Y-%m-%d%z")
OffsetDateTime(2020-08-15 00:00:00+02:00)

Important

The parsed tzinfo must be a fixed offset (datetime.timezone instance). This means you MUST include the directive %z, %Z, or %:z in the format string.

class whenever.ZonedDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, *, nanosecond: int = 0, tz: str, disambiguate: Literal['compatible', 'earlier', 'later', 'raise'] = 'compatible')ΒΆ

Bases: _KnowsInstantAndLocal

A datetime associated with a timezone in the IANA database. Useful for representing the exact time at a specific location.

Example

>>> ZonedDateTime(2024, 12, 8, hour=11, tz="Europe/Paris")
ZonedDateTime(2024-12-08 11:00:00+01:00[Europe/Paris])
>>> # Explicitly resolve ambiguities during DST transitions
>>> ZonedDateTime(2023, 10, 29, 1, 15, tz="Europe/London", disambiguate="earlier")
ZonedDateTime(2023-10-29 01:15:00+01:00[Europe/London])

Important

To use this type properly, read more about ambiguity in timezones.

property tz: strΒΆ

The timezone ID

is_ambiguous() bool[source]ΒΆ

Whether the local time is ambiguous, e.g. due to a DST transition.

Example

>>> ZonedDateTime(2020, 8, 15, 23, tz="Europe/London").is_ambiguous()
False
>>> ZonedDateTime(2023, 10, 29, 2, 15, tz="Europe/Amsterdam").is_ambiguous()
True
start_of_day() ZonedDateTime[source]ΒΆ

The start of the current calendar day.

This is almost always at midnight the same day, but may be different for timezones which transition atβ€”and thus skip overβ€”midnight.

day_length() TimeDelta[source]ΒΆ

The duration between the start of the current day and the next. This is usually 24 hours, but may be different due to timezone transitions.

Example

>>> ZonedDateTime(2020, 8, 15, tz="Europe/London").day_length()
TimeDelta(24:00:00)
>>> ZonedDateTime(2023, 10, 29, tz="Europe/Amsterdam").day_length()
TimeDelta(25:00:00)
class whenever.SystemDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, *, nanosecond: int = 0, disambiguate: Literal['compatible', 'earlier', 'later', 'raise'] = 'compatible')ΒΆ

Bases: _KnowsInstantAndLocal

Represents a time in the system timezone. It is similar to OffsetDateTime, but it knows about the system timezone and its DST transitions.

Example

>>> # 8:00 in the system timezoneβ€”Paris in this case
>>> alarm = SystemDateTime(2024, 3, 31, hour=6)
SystemDateTime(2024-03-31 06:00:00+02:00)
>>> # Conversion based on Paris' offset
>>> alarm.instant()
Instant(2024-03-31 04:00:00Z)
>>> # DST-safe arithmetic
>>> bedtime = alarm - hours(8)
SystemDateTime(2024-03-30 21:00:00+01:00)

Attention

To use this type properly, read more about ambiguity and working with the system timezone.

is_ambiguous() bool[source]ΒΆ

Whether the local time is ambiguous, e.g. due to a DST transition.

Example

>>> # with system configured in Europe/Paris
>>> SystemDateTime(2020, 8, 15, 23).is_ambiguous()
False
>>> SystemDateTime(2023, 10, 29, 2, 15).is_ambiguous()
True

Note

This method may give a different result after a change to the system timezone.

start_of_day() SystemDateTime[source]ΒΆ

The start of the current calendar day.

This is almost always at midnight the same day, but may be different for timezones which transition atβ€”and thus skip overβ€”midnight.

Note

This method may give a different result after a change to the system timezone.

day_length() TimeDelta[source]ΒΆ

The duration between the start of the current day and the next. This is usually 24 hours, but may be different due to timezone transitions.

Example

>>> # with system configured in Europe/Paris
>>> SystemDateTime(2020, 8, 15).day_length()
TimeDelta(24:00:00)
>>> SystemDateTime(2023, 10, 29).day_length()
TimeDelta(25:00:00)

Note

This method may give a different result after a change to the system timezone.

DeltasΒΆ

whenever.years(i: int, /) DateDeltaΒΆ

Create a DateDelta with the given number of years. years(1) == DateDelta(years=1)

whenever.months(i: int, /) DateDeltaΒΆ

Create a DateDelta with the given number of months. months(1) == DateDelta(months=1)

whenever.weeks(i: int, /) DateDeltaΒΆ

Create a DateDelta with the given number of weeks. weeks(1) == DateDelta(weeks=1)

whenever.days(i: int, /) DateDeltaΒΆ

Create a DateDelta with the given number of days. days(1) == DateDelta(days=1)

whenever.hours(i: float, /) TimeDeltaΒΆ

Create a TimeDelta with the given number of hours. hours(1) == TimeDelta(hours=1)

whenever.minutes(i: float, /) TimeDeltaΒΆ

Create a TimeDelta with the given number of minutes. minutes(1) == TimeDelta(minutes=1)

whenever.seconds(i: float, /) TimeDeltaΒΆ

Create a TimeDelta with the given number of seconds. seconds(1) == TimeDelta(seconds=1)

whenever.milliseconds(i: int, /) TimeDeltaΒΆ

Create a TimeDelta with the given number of milliseconds. milliseconds(1) == TimeDelta(milliseconds=1)

whenever.microseconds(i: float, /) TimeDeltaΒΆ

Create a TimeDelta with the given number of microseconds. microseconds(1) == TimeDelta(microseconds=1)

whenever.nanoseconds(i: int, /) TimeDeltaΒΆ

Create a TimeDelta with the given number of nanoseconds. nanoseconds(1) == TimeDelta(nanoseconds=1)

class whenever.TimeDelta(*, hours: float = 0, minutes: float = 0, seconds: float = 0, milliseconds: float = 0, microseconds: float = 0, nanoseconds: int = 0)ΒΆ

A duration consisting of a precise time: hours, minutes, (nano)seconds

The inputs are normalized, so 90 minutes becomes 1 hour and 30 minutes, for example.

Examples

>>> d = TimeDelta(hours=1, minutes=30)
TimeDelta(01:30:00)
>>> d.in_minutes()
90.0

Note

A shorter way to instantiate a timedelta is to use the helper functions hours(), minutes(), etc.

__abs__() TimeDelta[source]ΒΆ

The absolute value

Example

>>> d = TimeDelta(hours=-1, minutes=-30)
>>> abs(d)
TimeDelta(01:30:00)
__add__(other: TimeDelta) TimeDelta[source]ΒΆ

Add two deltas together

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d + TimeDelta(minutes=30)
TimeDelta(02:00:00)
__bool__() bool[source]ΒΆ

True if the value is non-zero

Example

>>> bool(TimeDelta())
False
>>> bool(TimeDelta(minutes=1))
True
__eq__(other: object) bool[source]ΒΆ

Compare for equality

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d == TimeDelta(minutes=90)
True
>>> d == TimeDelta(hours=2)
False
__gt__(other: TimeDelta) bool[source]ΒΆ

Return self>value.

__mul__(other: float) TimeDelta[source]ΒΆ

Multiply by a number

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d * 2.5
TimeDelta(03:45:00)
__neg__() TimeDelta[source]ΒΆ

Negate the value

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> -d
TimeDelta(-01:30:00)
__sub__(other: TimeDelta) TimeDelta[source]ΒΆ

Subtract two deltas

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d - TimeDelta(minutes=30)
TimeDelta(01:00:00)
__truediv__(other: float | TimeDelta) TimeDelta | float[source]ΒΆ

Divide by a number or another delta

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d / 2.5
TimeDelta(00:36:00)
>>> d / TimeDelta(minutes=30)
3.0

Note

Because TimeDelta is limited to nanosecond precision, the result of division may not be exact.

format_common_iso() str[source]ΒΆ

Format as the popular interpretation of the ISO 8601 duration format. May not strictly adhere to (all versions of) the standard. See here for more information.

Inverse of parse_common_iso().

Example

>>> TimeDelta(hours=1, minutes=30).format_common_iso()
'PT1H30M'
classmethod from_py_timedelta(td: timedelta, /) TimeDelta[source]ΒΆ

Create from a timedelta

Inverse of py_timedelta()

Example

>>> TimeDelta.from_py_timedelta(timedelta(seconds=5400))
TimeDelta(01:30:00)
in_days_of_24h() float[source]ΒΆ

The total size in days (of exactly 24 hours each)

Note

Note that this may not be the same as days on the calendar, since some days have 23 or 25 hours due to daylight saving time.

in_hours() float[source]ΒΆ

The total size in hours

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d.in_hours()
1.5
in_hrs_mins_secs_nanos() tuple[int, int, int, int][source]ΒΆ

Convert to a tuple of (hours, minutes, seconds, nanoseconds)

Example

>>> d = TimeDelta(hours=1, minutes=30, microseconds=5_000_090)
>>> d.in_hrs_mins_secs_nanos()
(1, 30, 5, 90_000)
in_microseconds() float[source]ΒΆ

The total size in microseconds

>>> d = TimeDelta(seconds=2, nanoseconds=50)
>>> d.in_microseconds()
2_000_000.05
in_milliseconds() float[source]ΒΆ

The total size in milliseconds

>>> d = TimeDelta(seconds=2, microseconds=50)
>>> d.in_milliseconds()
2_000.05
in_minutes() float[source]ΒΆ

The total size in minutes

Example

>>> d = TimeDelta(hours=1, minutes=30, seconds=30)
>>> d.in_minutes()
90.5
in_nanoseconds() int[source]ΒΆ

The total size in nanoseconds

>>> d = TimeDelta(seconds=2, nanoseconds=50)
>>> d.in_nanoseconds()
2_000_000_050
in_seconds() float[source]ΒΆ

The total size in seconds

Example

>>> d = TimeDelta(minutes=2, seconds=1, microseconds=500_000)
>>> d.in_seconds()
121.5
classmethod parse_common_iso(s: str, /) TimeDelta[source]ΒΆ

Parse the popular interpretation of the ISO 8601 duration format. Does not parse all possible ISO 8601 durations. See here for more information.

Inverse of format_common_iso()

Example

>>> TimeDelta.parse_common_iso("PT1H30M")
TimeDelta(01:30:00)

Note

Any duration with a date part is considered invalid. PT0S is valid, but P0D is not.

py_timedelta() timedelta[source]ΒΆ

Convert to a timedelta

Inverse of from_py_timedelta()

Note

Nanoseconds are truncated to microseconds. If you need more control over rounding, use round() first.

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d.py_timedelta()
timedelta(seconds=5400)
round(unit: Literal['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'] = 'second', increment: int = 1, mode: Literal['ceil', 'floor', 'half_ceil', 'half_floor', 'half_even'] = 'half_even') TimeDelta[source]ΒΆ

Round the delta to the specified unit and increment. Various rounding modes are available.

Examples

>>> t = TimeDelta(seconds=12345)
TimeDelta(03:25:45)
>>> t.round("minute")
TimeDelta(03:26:00)
>>> t.round("second", increment=10, mode="floor")
Time(03:25:40)
class whenever.DateDelta(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0)ΒΆ

A duration of time consisting of calendar units (years, months, weeks, and days)

__abs__() DateDelta[source]ΒΆ

If the contents are negative, return the positive version

Example

>>> p = DateDelta(months=-2, days=-3)
>>> abs(p)
DateDelta(P2M3D)
__add__(other: DateDelta | TimeDelta) DateDelta | DateTimeDelta[source]ΒΆ

Add the fields of another delta to this one

Example

>>> p = DateDelta(weeks=2, months=1)
>>> p + DateDelta(weeks=1, days=4)
DateDelta(P1M25D)
__bool__() bool[source]ΒΆ

True if any contains any non-zero data

Example

>>> bool(DateDelta())
False
>>> bool(DateDelta(days=-1))
True
__eq__(other: object) bool[source]ΒΆ

Compare for equality, normalized to months and days.

a == b is equivalent to a.in_months_days() == b.in_months_days()

Example

>>> p = DateDelta(weeks=4, days=2)
DateDelta(P30D)
>>> p == DateDelta(weeks=3, days=9)
True
>>> p == DateDelta(weeks=2, days=4)
True  # same number of days
>>> p == DateDelta(months=1)
False  # months and days cannot be compared directly
__mul__(other: int) DateDelta[source]ΒΆ

Multiply the contents by a round number

Example

>>> p = DateDelta(years=1, weeks=2)
>>> p * 2
DateDelta(P2Y28D)
__neg__() DateDelta[source]ΒΆ

Negate the contents

Example

>>> p = DateDelta(weeks=2, days=3)
>>> -p
DateDelta(-P17D)
__sub__(other: DateDelta | TimeDelta) DateDelta | DateTimeDelta[source]ΒΆ

Subtract the fields of another delta from this one

Example

>>> p = DateDelta(weeks=2, days=3)
>>> p - DateDelta(days=2)
DateDelta(P15D)
format_common_iso() str[source]ΒΆ

Format as the popular interpretation of the ISO 8601 duration format. May not strictly adhere to (all versions of) the standard. See here for more information.

Inverse of parse_common_iso().

The format looks like this:

P(nY)(nM)(nD)

For example:

P1D
P2M
P1Y2M3W4D

Example

>>> p = DateDelta(years=1, months=2, weeks=3, days=11)
>>> p.common_iso()
'P1Y2M3W11D'
>>> DateDelta().common_iso()
'P0D'
in_months_days() tuple[int, int][source]ΒΆ

Convert to a tuple of months and days.

Example

>>> p = DateDelta(months=25, days=9)
>>> p.in_months_days()
(25, 9)
>>> DateDelta(months=-13, weeks=-5)
(-13, -35)
in_years_months_days() tuple[int, int, int][source]ΒΆ

Convert to a tuple of years, months, and days.

Example

>>> p = DateDelta(years=1, months=2, days=11)
>>> p.in_years_months_days()
(1, 2, 11)
classmethod parse_common_iso(s: str, /) DateDelta[source]ΒΆ

Parse the popular interpretation of the ISO 8601 duration format. Does not parse all possible ISO 8601 durations. See here for more information.

Inverse of format_common_iso()

Example

>>> DateDelta.parse_common_iso("P1W11D")
DateDelta(P1W11D)
>>> DateDelta.parse_common_iso("-P3M")
DateDelta(-P3M)

Note

Only durations without time component are accepted. P0D is valid, but PT0S is not.

Note

The number of digits in each component is limited to 8.

class whenever.DateTimeDelta(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0, hours: float = 0, minutes: float = 0, seconds: float = 0, milliseconds: float = 0, microseconds: float = 0, nanoseconds: int = 0)ΒΆ

A duration with both a date and time component.

__abs__() DateTimeDelta[source]ΒΆ

The absolute value of the delta

Example

>>> d = DateTimeDelta(weeks=1, days=-11, hours=4)
>>> abs(d)
DateTimeDelta(P1W11DT4H)
__add__(other: DateTimeDelta | TimeDelta | DateDelta) DateTimeDelta[source]ΒΆ

Add two deltas together

Example

>>> d = DateTimeDelta(weeks=1, days=11, hours=4)
>>> d + DateTimeDelta(months=2, days=3, minutes=90)
DateTimeDelta(P1M1W14DT5H30M)
__bool__() bool[source]ΒΆ

True if any field is non-zero

Example

>>> bool(DateTimeDelta())
False
>>> bool(DateTimeDelta(minutes=1))
True
__eq__(other: object) bool[source]ΒΆ

Compare for equality

Example

>>> d = DateTimeDelta(
...     weeks=1,
...     days=23,
...     hours=4,
... )
>>> d == DateTimeDelta(
...     weeks=1,
...     days=23,
...     minutes=4 * 60,  # normalized
... )
True
>>> d == DateTimeDelta(
...     weeks=4,
...     days=2,  # days/weeks are normalized
...     hours=4,
... )
True
>>> d == DateTimeDelta(
...     months=1,  # months/days cannot be compared directly
...     hours=4,
... )
False
__mul__(other: int) DateTimeDelta[source]ΒΆ

Multiply by a number

Example

>>> d = DateTimeDelta(weeks=1, days=11, hours=4)
>>> d * 2
DateTimeDelta(P2W22DT8H)
__neg__() DateTimeDelta[source]ΒΆ

Negate the delta

Example

>>> d = DateTimeDelta(days=11, hours=4)
>>> -d
DateTimeDelta(-P11DT4H)
__sub__(other: DateTimeDelta | TimeDelta | DateDelta) DateTimeDelta[source]ΒΆ

Subtract two deltas

Example

>>> d = DateTimeDelta(weeks=1, days=11, hours=4)
>>> d - DateTimeDelta(months=2, days=3, minutes=90)
DateTimeDelta(-P2M1W8DT2H30M)
date_part() DateDelta[source]ΒΆ

The date part of the delta

format_common_iso() str[source]ΒΆ

Format as the popular interpretation of the ISO 8601 duration format. May not strictly adhere to (all versions of) the standard. See here for more information.

Inverse of parse_common_iso().

The format is:

P(nY)(nM)(nD)T(nH)(nM)(nS)

Example

>>> d = DateTimeDelta(
...     weeks=1,
...     days=11,
...     hours=4,
...     milliseconds=12,
... )
>>> d.format_common_iso()
'P1W11DT4H0.012S'
in_months_days_secs_nanos() tuple[int, int, int, int][source]ΒΆ

Convert to a tuple of (months, days, seconds, nanoseconds)

Example

>>> d = DateTimeDelta(weeks=1, days=11, hours=4, microseconds=2)
>>> d.in_months_days_secs_nanos()
(0, 18, 14_400, 2000)
classmethod parse_common_iso(s: str, /) DateTimeDelta[source]ΒΆ

Parse the popular interpretation of the ISO 8601 duration format. Does not parse all possible ISO 8601 durations. See here for more information.

Examples:

P4D        # 4 days
PT4H       # 4 hours
PT3M40.5S  # 3 minutes and 40.5 seconds
P1W11DT4H  # 1 week, 11 days, and 4 hours
-PT7H4M    # -7 hours and -4 minutes (-7:04:00)
+PT7H4M    # 7 hours and 4 minutes (7:04:00)

Inverse of format_common_iso()

Example

>>> DateTimeDelta.parse_common_iso("-P1W11DT4H")
DateTimeDelta(-P1W11DT4H)
time_part() TimeDelta[source]ΒΆ

The time part of the delta

Date and time componentsΒΆ

class whenever.Date(year: int, month: int, day: int)ΒΆ

A date without a time component

Example

>>> d = Date(2021, 1, 2)
Date(2021-01-02)
__add__(p: DateDelta) Date[source]ΒΆ

Add a delta to a date. Behaves the same as add()

__eq__(other: object) bool[source]ΒΆ

Compare for equality

Example

>>> d = Date(2021, 1, 2)
>>> d == Date(2021, 1, 2)
True
>>> d == Date(2021, 1, 3)
False
__ge__(other: Date) bool[source]ΒΆ

Return self>=value.

__gt__(other: Date) bool[source]ΒΆ

Return self>value.

__le__(other: Date) bool[source]ΒΆ

Return self<=value.

__lt__(other: Date) bool[source]ΒΆ

Return self<value.

__sub__(d: DateDelta | Date) Date | DateDelta[source]ΒΆ

Subtract a delta from a date, or subtract two dates

Subtracting a delta works the same as subtract().

>>> Date(2021, 1, 2) - DateDelta(weeks=1, days=3)
Date(2020-12-26)

The difference between two dates is calculated in months and days, such that:

>>> delta = d1 - d2
>>> d2 + delta == d1  # always

The following is not always true:

>>> d1 - (d1 - d2) == d2  # not always true!
>>> -(d2 - d1) == d1 - d2  # not always true!

Examples:

>>> Date(2023, 4, 15) - Date(2011, 6, 24)
DateDelta(P12Y9M22D)
>>> # Truncation
>>> Date(2024, 4, 30) - Date(2023, 5, 31)
DateDelta(P11M)
>>> Date(2024, 3, 31) - Date(2023, 6, 30)
DateDelta(P9M1D)
>>> # the other way around, the result is different
>>> Date(2023, 6, 30) - Date(2024, 3, 31)
DateDelta(-P9M)

Note

If you’d like to calculate the difference in days only (no months), use the days_until() or days_since() instead.

add(*args, **kwargs) Date[source]ΒΆ

Add a components to a date.

See the docs on arithmetic for more information.

Example

>>> d = Date(2021, 1, 2)
>>> d.add(years=1, months=2, days=3)
Date(2022-03-05)
>>> Date(2020, 2, 29).add(years=1)
Date(2021-02-28)
at(t: Time, /) LocalDateTime[source]ΒΆ

Combine a date with a time to create a datetime

Example

>>> d = Date(2021, 1, 2)
>>> d.at(Time(12, 30))
LocalDateTime(2021-01-02 12:30:00)

You can use methods like assume_utc() or assume_tz() to make the result aware.

day_of_week() Weekday[source]ΒΆ

The day of the week

Example

>>> Date(2021, 1, 2).day_of_week()
Weekday.SATURDAY
>>> Weekday.SATURDAY.value
6  # the ISO value
days_since(other: Date, /) int[source]ΒΆ

Calculate the number of days this day is after another date. If the other date is after this date, the result is negative.

Example

>>> Date(2021, 1, 5).days_since(Date(2021, 1, 2))
3

Note

If you’re interested in calculating the difference in terms of days and months, use the subtraction operator instead.

days_until(other: Date, /) int[source]ΒΆ

Calculate the number of days from this date to another date. If the other date is before this date, the result is negative.

Example

>>> Date(2021, 1, 2).days_until(Date(2021, 1, 5))
3

Note

If you’re interested in calculating the difference in terms of days and months, use the subtraction operator instead.

format_common_iso() str[source]ΒΆ

Format as the common ISO 8601 date format.

Inverse of parse_common_iso().

Example

>>> Date(2021, 1, 2).format_common_iso()
'2021-01-02'
classmethod from_py_date(d: date, /) Date[source]ΒΆ

Create from a date

Example

>>> Date.from_py_date(date(2021, 1, 2))
Date(2021-01-02)
month_day() MonthDay[source]ΒΆ

The month and day (without a year component)

Example

>>> Date(2021, 1, 2).month_day()
MonthDay(--01-02)
classmethod parse_common_iso(s: str, /) Date[source]ΒΆ

Create from the common ISO 8601 date format YYYY-MM-DD. Does not accept more β€œexotic” ISO 8601 formats.

Inverse of format_common_iso()

Example

>>> Date.parse_common_iso("2021-01-02")
Date(2021-01-02)
py_date() date[source]ΒΆ

Convert to a standard library date

replace(**kwargs: Any) Date[source]ΒΆ

Create a new instance with the given fields replaced

Example

>>> d = Date(2021, 1, 2)
>>> d.replace(day=4)
Date(2021-01-04)
subtract(*args, **kwargs) Date[source]ΒΆ

Subtract components from a date.

See the docs on arithmetic for more information.

Example

>>> d = Date(2021, 1, 2)
>>> d.subtract(years=1, months=2, days=3)
Date(2019-10-30)
>>> Date(2021, 3, 1).subtract(years=1)
Date(2020-03-01)
classmethod today_in_system_tz() Date[source]ΒΆ

Get the current date in the system’s local timezone.

Alias for SystemDateTime.now().date().

Example

>>> Date.today_in_system_tz()
Date(2021-01-02)
year_month() YearMonth[source]ΒΆ

The year and month (without a day component)

Example

>>> Date(2021, 1, 2).year_month()
YearMonth(2021-01)
class whenever.YearMonth(year: int, month: int)ΒΆ

A year and month without a day component

Useful for representing recurring events or billing periods.

Example

>>> ym = YearMonth(2021, 1)
YearMonth(2021-01)
__eq__(other: object) bool[source]ΒΆ

Compare for equality

Example

>>> ym = YearMonth(2021, 1)
>>> ym == YearMonth(2021, 1)
True
>>> ym == YearMonth(2021, 2)
False
__ge__(other: YearMonth) bool[source]ΒΆ

Return self>=value.

__gt__(other: YearMonth) bool[source]ΒΆ

Return self>value.

__le__(other: YearMonth) bool[source]ΒΆ

Return self<=value.

__lt__(other: YearMonth) bool[source]ΒΆ

Return self<value.

format_common_iso() str[source]ΒΆ

Format as the common ISO 8601 year-month format.

Inverse of parse_common_iso().

Example

>>> YearMonth(2021, 1).format_common_iso()
'2021-01'
on_day(day: int, /) Date[source]ΒΆ

Create a date from this year-month with a given day

Example

>>> YearMonth(2021, 1).on_day(2)
Date(2021-01-02)
classmethod parse_common_iso(s: str, /) YearMonth[source]ΒΆ

Create from the common ISO 8601 format YYYY-MM. Does not accept more β€œexotic” ISO 8601 formats.

Inverse of format_common_iso()

Example

>>> YearMonth.parse_common_iso("2021-01")
YearMonth(2021-01)
replace(**kwargs: Any) YearMonth[source]ΒΆ

Create a new instance with the given fields replaced

Example

>>> d = YearMonth(2021, 12)
>>> d.replace(month=3)
YearMonth(2021-03)
class whenever.MonthDay(month: int, day: int)ΒΆ

A month and day without a year component.

Useful for representing recurring events or birthdays.

Example

>>> MonthDay(11, 23)
MonthDay(--11-23)
__eq__(other: object) bool[source]ΒΆ

Compare for equality

Example

>>> md = MonthDay(10, 1)
>>> md == MonthDay(10, 1)
True
>>> md == MonthDay(10, 2)
False
__ge__(other: MonthDay) bool[source]ΒΆ

Return self>=value.

__gt__(other: MonthDay) bool[source]ΒΆ

Return self>value.

__le__(other: MonthDay) bool[source]ΒΆ

Return self<=value.

__lt__(other: MonthDay) bool[source]ΒΆ

Return self<value.

format_common_iso() str[source]ΒΆ

Format as the common ISO 8601 month-day format.

Inverse of parse_common_iso.

Example

>>> MonthDay(10, 8).format_common_iso()
'--10-08'

Note

This format is officially only part of the 2000 edition of the ISO 8601 standard. There is no alternative for month-day in the newer editions. However, it is still widely used in other libraries.

in_year(year: int, /) Date[source]ΒΆ

Create a date from this month-day with a given day

Example

>>> MonthDay(8, 1).in_year(2025)
Date(2025-08-01)

Note

This method will raise a ValueError if the month-day is a leap day and the year is not a leap year.

is_leap() bool[source]ΒΆ

Check if the month-day is February 29th

Example

>>> MonthDay(2, 29).is_leap()
True
>>> MonthDay(3, 1).is_leap()
False
classmethod parse_common_iso(s: str, /) MonthDay[source]ΒΆ

Create from the common ISO 8601 format --MM-DD. Does not accept more β€œexotic” ISO 8601 formats.

Inverse of format_common_iso()

Example

>>> MonthDay.parse_common_iso("--11-23")
MonthDay(--11-23)
replace(**kwargs: Any) MonthDay[source]ΒΆ

Create a new instance with the given fields replaced

Example

>>> d = MonthDay(11, 23)
>>> d.replace(month=3)
MonthDay(--03-23)
class whenever.Time(hour: int = 0, minute: int = 0, second: int = 0, *, nanosecond: int = 0)ΒΆ

Time of day without a date component

Example

>>> t = Time(12, 30, 0)
Time(12:30:00)
__eq__(other: object) bool[source]ΒΆ

Compare for equality

Example

>>> t = Time(12, 30, 0)
>>> t == Time(12, 30, 0)
True
>>> t == Time(12, 30, 1)
False
__ge__(other: Time) bool[source]ΒΆ

Return self>=value.

__gt__(other: Time) bool[source]ΒΆ

Return self>value.

__le__(other: Time) bool[source]ΒΆ

Return self<=value.

__lt__(other: Time) bool[source]ΒΆ

Return self<value.

format_common_iso() str[source]ΒΆ

Format as the common ISO 8601 time format.

Inverse of parse_common_iso().

Example

>>> Time(12, 30, 0).format_common_iso()
'12:30:00'
classmethod from_py_time(t: time, /) Time[source]ΒΆ

Create from a time

Example

>>> Time.from_py_time(time(12, 30, 0))
Time(12:30:00)

fold value is ignored.

on(d: Date, /) LocalDateTime[source]ΒΆ

Combine a time with a date to create a datetime

Example

>>> t = Time(12, 30)
>>> t.on(Date(2021, 1, 2))
LocalDateTime(2021-01-02 12:30:00)

Then, use methods like assume_utc() or assume_tz() to make the result aware.

classmethod parse_common_iso(s: str, /) Time[source]ΒΆ

Create from the common ISO 8601 time format HH:MM:SS. Does not accept more β€œexotic” ISO 8601 formats.

Inverse of format_common_iso()

Example

>>> Time.parse_common_iso("12:30:00")
Time(12:30:00)
py_time() time[source]ΒΆ

Convert to a standard library time

replace(**kwargs: Any) Time[source]ΒΆ

Create a new instance with the given fields replaced

Example

>>> t = Time(12, 30, 0)
>>> d.replace(minute=3, nanosecond=4_000)
Time(12:03:00.000004)
round(unit: Literal['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'] = 'second', increment: int = 1, mode: Literal['ceil', 'floor', 'half_ceil', 'half_floor', 'half_even'] = 'half_even') Time[source]ΒΆ

Round the time to the specified unit and increment. Various rounding modes are available.

Examples

>>> Time(12, 39, 59).round("minute", 15)
Time(12:45:00)
>>> Time(8, 9, 13).round("second", 5, mode="floor")
Time(08:09:10)

MiscellaneousΒΆ

enum whenever.Weekday(value)ΒΆ

The days of the week; .value corresponds with ISO numbering.

Valid values are as follows:

MONDAY = <Weekday.MONDAY: 1>ΒΆ
TUESDAY = <Weekday.TUESDAY: 2>ΒΆ
WEDNESDAY = <Weekday.WEDNESDAY: 3>ΒΆ
THURSDAY = <Weekday.THURSDAY: 4>ΒΆ
FRIDAY = <Weekday.FRIDAY: 5>ΒΆ
SATURDAY = <Weekday.SATURDAY: 6>ΒΆ
SUNDAY = <Weekday.SUNDAY: 7>ΒΆ
exception whenever.RepeatedTimeΒΆ

Bases: Exception

A datetime is repeated in a timezone, e.g. because of DST

exception whenever.SkippedTimeΒΆ

Bases: Exception

A datetime is skipped in a timezone, e.g. because of DST

exception whenever.InvalidOffsetΒΆ

Bases: ValueError

A string has an invalid offset for the given zone

class whenever.patch_current_time(dt: Instant | ZonedDateTime | OffsetDateTime | SystemDateTime, /, *, 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 time.tzset. Be aware that this only works on Unix-like systems.

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)