📖 API reference

All classes are immutable.

Datetimes

Base classes

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

class whenever._DateTime[source]

Encapsulates behavior common to all datetimes. Not for public use.

property year: int
property month: int
property day: int
property hour: int
property minute: int
property second: int
property microsecond: int
date() Date[source]

The date part of the datetime

Example

>>> d = UTCDateTime(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_zoned():

>>> date.at(time).assume_zoned("Europe/London")
time() Time[source]

The time-of-day part of the datetime

Example

>>> d = UTCDateTime(2021, 1, 2, 3, 4, 5)
UTCDateTime(2021-01-02T03:04:05Z)
>>> d.time()
Time(03:04:05)

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

>>> time.on(date).assume_utc()
abstract canonical_format(sep: Literal[' ', 'T'] = 'T') str[source]

Format as the canonical string representation. Each subclass has a different format. See the documentation for the subclass for more information. Inverse of from_canonical_format().

__str__() str[source]

Same as canonical_format() with sep=" "

abstract classmethod from_canonical_format(s: str, /) _TDateTime[source]

Create an instance from the canonical string representation, which is different for each subclass.

Inverse of __str__() and canonical_format().

Note

T may be replaced with a single space

Raises:

ValueError – If the string does not match this exact format.

abstract classmethod from_py_datetime(d: datetime, /) _TDateTime[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 consulted to determine the behavior on ambiguity.

py_datetime() datetime[source]

Get the underlying datetime object

abstract replace(**kwargs) _TDateTime[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 local and zoned datetimes, you will need to pass disambiguate= to resolve ambiguities.

Example

>>> d = UTCDateTime(2020, 8, 15, 23, 12)
>>> d.replace(year=2021)
UTCDateTime(2021-08-15T23:12:00)
>>>
>>> z = ZonedDateTime(2020, 8, 15, 23, 12, tz="Europe/London")
>>> z.replace(year=2021, disambiguate="later")
ZonedDateTime(2021-08-15T23:12:00+01:00)
class whenever._AwareDateTime[source]

Common behavior for all aware datetime types (UTCDateTime, OffsetDateTime, ZonedDateTime and LocalSystemDateTime).

Not for public use.

timestamp() float[source]

The UNIX timestamp for this datetime.

Each subclass also defines an inverse from_timestamp method, which may require additional arguments.

Example

>>> UTCDateTime(1970, 1, 1).timestamp()
0.0
>>> ts = 1_123_000_000
>>> UTCDateTime.from_timestamp(ts).timestamp() == ts
True
abstract property offset: TimeDelta

The UTC offset of the datetime

abstract as_utc() UTCDateTime[source]

Convert into an equivalent UTCDateTime. The result will always represent the same moment in time.

abstract as_offset() OffsetDateTime[source]
abstract as_offset(offset: int | TimeDelta, /) OffsetDateTime

Convert into an equivalent OffsetDateTime. Optionally, specify the offset to use. The result will always represent the same moment in time.

as_zoned(tz: str, /) ZonedDateTime[source]

Convert into an equivalent ZonedDateTime. The result will always represent the same moment in time.

Raises:

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

as_local() LocalSystemDateTime[source]

Convert into a an equivalent LocalSystemDateTime. The result will always represent the same moment in time.

naive() NaiveDateTime[source]

Convert into a naive datetime, dropping all timezone information

As an inverse, NaiveDateTime has methods assume_utc(), assume_offset() , assume_zoned(), and assume_local() which may require additional arguments.

abstract __eq__(other: object) bool[source]

Check if two datetimes represent at the same moment in time

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

Note

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

Example

>>> UTCDateTime(2020, 8, 15, hour=23) == UTCDateTime(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
abstract __lt__(other: _AwareDateTime) bool[source]

Compare two datetimes by when they occur in time

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

Example

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

Compare two datetimes by when they occur in time

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

Example

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

Compare two datetimes by when they occur in time

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

Example

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

Compare two datetimes by when they occur in time

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

Example

>>> OffsetDateTime(2020, 8, 15, hour=19, offset=-8) >= (
...     ZoneDateTime(2020, 8, 15, hour=20, tz="Europe/Amsterdam")
... )
True
abstract __sub__(other: _AwareDateTime) TimeDelta[source]

Calculate the duration between two datetimes

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

Example

>>> d = UTCDateTime(2020, 8, 15, hour=23)
>>> d - ZonedDateTime(2020, 8, 15, hour=20, tz="Europe/Amsterdam")
TimeDelta(05:00:00)
abstract exact_eq(other: _TDateTime, /) bool[source]

Compare objects by their values (instead of their UTC equivalence). 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 UTC times
>>> a.exact_eq(b)
False  # different values (hour and offset)

Concrete classes

class whenever.UTCDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, microsecond: int = 0)[source]

A UTC-only datetime. Useful for representing moments in time in an unambiguous way.

In >95% of cases, you should use this class over the others. The other classes are most often useful at the boundaries of your application.

Example

>>> from whenever import UTCDateTime
>>> py311_release_livestream = UTCDateTime(2022, 10, 24, hour=17)
UTCDateTime(2022-10-24 17:00:00Z)

Note

The canonical string format is:

YYYY-MM-DDTHH:MM:SS(.ffffff)Z

This format is both RFC 3339 and ISO 8601 compliant.

Note

The underlying datetime object is always timezone-aware and has a fixed UTC tzinfo.

classmethod now() UTCDateTime[source]

Create an instance from the current time

classmethod from_timestamp(i: float, /) UTCDateTime[source]

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

Example

>>> UTCDateTime.from_timestamp(0) == UTCDateTime(1970, 1, 1)
>>> d = UTCDateTime.from_timestamp(1_123_000_000.45)
UTCDateTime(2004-08-02T16:26:40.45Z)
>>> UTCDateTime.from_timestamp(d.timestamp()) == d
True
add(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0, hours: int = 0, minutes: int = 0, seconds: int = 0, microseconds: int = 0) UTCDateTime[source]

Add a time amount to this datetime.

Units are added from largest to smallest, truncating and/or wrapping after each step.

Example

>>> d = UTCDateTime(2020, 8, 15, hour=23, minute=12)
>>> d.add(hours=24, seconds=5)
UTCDateTime(2020-08-16 23:12:05Z)
>>> d.add(years=1, days=2, minutes=5)
UTCDateTime(2021-08-17 23:17:00Z)
subtract(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0, hours: int = 0, minutes: int = 0, seconds: int = 0, microseconds: int = 0) UTCDateTime[source]

Subtract a time amount from this datetime.

Units are subtracted from largest to smallest, wrapping and/or truncating after each step.

Example

>>> d = UTCDateTime(2020, 8, 15, hour=23, minute=12)
>>> d.subtract(hours=24, seconds=5)
UTCDateTime(2020-08-14 23:11:55Z)
>>> d.subtract(years=1, days=2, minutes=5)
UTCDateTime(2019-08-13 23:06:00Z)
__add__(delta: DateTimeDelta | TimeDelta | DateDelta) UTCDateTime[source]

Add a time amount to this datetime.

Behaves the same as add().

Example

>>> d = UTCDateTime(2020, 8, 15, hour=23, minute=12)
>>> d + hours(24) + seconds(5)
UTCDateTime(2020-08-16 23:12:05Z)
>>> d + years(1) + days(2) + minutes(5)
UTCDateTime(2021-08-17 23:17:00Z)
__sub__(other: _AwareDateTime) TimeDelta[source]
__sub__(other: DateTimeDelta | TimeDelta | DateDelta) UTCDateTime

Subtract another datetime or delta

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

Example

>>> d = UTCDateTime(2020, 8, 15, hour=23, minute=12)
>>> d - hours(24) - seconds(5)
UTCDateTime(2020-08-14 23:11:55Z)
>>> d - UTCDateTime(2020, 8, 14)
TimeDelta(47:12:00)
>>> d - months(2) - days(2) - minutes(5)
UTCDateTime(2020-06-12 23:06:00Z)
classmethod strptime(s: str, /, fmt: str) UTCDateTime[source]

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

Example

>>> UTCDateTime.strptime("2020-08-15+0000", "%Y-%m-%d%z")
UTCDateTime(2020-08-15 00:00:00Z)
>>> UTCDateTime.strptime("2020-08-15", "%Y-%m-%d")
UTCDateTime(2020-08-15 00:00:00Z)

Note

The parsed tzinfo must be either datetime.UTC or None (in which case it’s set to datetime.UTC).

rfc2822() str[source]

Format as an RFC 2822 string.

The inverse of from_rfc2822().

Example

>>> UTCDateTime(2020, 8, 15, hour=23, minute=12).rfc2822()
"Sat, 15 Aug 2020 23:12:00 GMT"
classmethod from_rfc2822(s: str, /) UTCDateTime[source]

Parse a UTC datetime in RFC 2822 format.

The inverse of rfc2822().

Example

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

Warning

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

rfc3339() str[source]

Format as an RFC 3339 string

For UTCDateTime, equivalent to canonical_format(). Inverse of from_rfc3339().

Example

>>> UTCDateTime(2020, 8, 15, hour=23, minute=12).rfc3339()
"2020-08-15T23:12:00Z"
classmethod from_rfc3339(s: str, /) UTCDateTime[source]

Parse a UTC datetime in RFC 3339 format.

Inverse of rfc3339().

Example

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

Warning

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

common_iso8601() str[source]

Format as a common ISO 8601 string.

For this class, equivalent to rfc3339().

Example

>>> UTCDateTime(2020, 8, 15, hour=23, minute=12).common_iso8601()
"2020-08-15T23:12:00Z"
classmethod from_common_iso8601(s: str, /) UTCDateTime[source]

Parse a UTC datetime in common ISO 8601 format.

Inverse of common_iso8601().

Example

>>> UTCDateTime.from_common_iso8601("2020-08-15T23:12:00Z")
UTCDateTime(2020-08-15 23:12:00Z)
>>>
>>> # also valid:
>>> UTCDateTime.from_common_iso8601("2020-08-15T23:12:00+00:00")
>>> UTCDateTime.from_common_iso8601("2020-08-15T23:12:00.34Z")
>>>
>>> # not valid
>>> UTCDateTime.from_common_iso8601("2020-08-15T23:12:00+02:00")
>>> UTCDateTime.from_common_iso8601("2020-08-15 23:12:00+00:00")
>>> UTCDateTime.from_common_iso8601("2020-08-15T23:12:00-00:00")

Warning

Nonzero offsets will not be implicitly converted to UTC. Use OffsetDateTime.from_common_iso8601() if you’d like to parse an ISO 8601 string with a nonzero offset.

class whenever.OffsetDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, microsecond: int = 0, *, offset: int | TimeDelta)[source]

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

Example

>>> # 9 AM in Salt Lake City, with the UTC offset at the time
>>> pycon23_start = OffsetDateTime(2023, 4, 21, hour=9, offset=-6)
OffsetDateTime(2023-04-21 09:00:00-06:00)

Note

The canonical string format is:

YYYY-MM-DDTHH:MM:SS(.ffffff)±HH:MM(:SS(.ffffff))

For example:

2020-08-15T12:08:30+01:00

This format is both RFC 3339 and ISO 8601 compliant.

Note

The underlying datetime object is always timezone-aware and has a fixed datetime.timezone tzinfo.

classmethod now(offset: int | TimeDelta) OffsetDateTime[source]

Create an instance at the current time with the given offset

classmethod from_timestamp(i: float, /, offset: int | TimeDelta) OffsetDateTime[source]

Create a OffsetDateTime from a UNIX timestamp. The inverse of timestamp().

Example

>>> OffsetDateTime.from_timestamp(0, offset=hours(3))
OffsetDateTime(1970-01-01 03:00:00+03:00)
>>> d = OffsetDateTime.from_timestamp(1_123_000_000.45, offset=-2)
OffsetDateTime(2004-08-02 14:26:40.45-02:00)
>>> OffsetDateTime.from_timestamp(d.timestamp(), d.offset) == d
True
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)

Note

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

rfc2822() str[source]

Format as an RFC 2822 string.

Inverse of from_rfc2822().

Example

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

Parse an offset datetime in RFC 2822 format.

Inverse of rfc2822().

Example

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

Warning

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.

rfc3339() str[source]

Format as an RFC 3339 string

For OffsetDateTime, equivalent to canonical_format() and common_iso8601(). Inverse of from_rfc3339().

Example

>>> OffsetDateTime(2020, 8, 15, hour=23, minute=12, offset=hours(4)).rfc3339()
"2020-08-15T23:12:00+04:00"
classmethod from_rfc3339(s: str, /) OffsetDateTime[source]

Parse a UTC datetime in RFC 3339 format.

Inverse of rfc3339().

Example

>>> OffsetDateTime.from_rfc3339("2020-08-15T23:12:00+02:00")
OffsetDateTime(2020-08-15 23:12:00+02:00)
>>> # also valid:
>>> OffsetDateTime.from_rfc3339("2020-08-15T23:12:00Z")
>>> OffsetDateTime.from_rfc3339("2020-08-15_23:12:00.23-12:00")
>>> OffsetDateTime.from_rfc3339("2020-08-15t23:12:00z")
common_iso8601() str[source]

Format in the commonly used ISO 8601 format.

Inverse of from_common_iso8601().

Note

For OffsetDateTime, equivalent to canonical_format() and rfc3339().

Example

>>> OffsetDateTime(2020, 8, 15, hour=23, offset=+3).common_iso8601()
"2020-08-15T23:00:00+03:00"
classmethod from_common_iso8601(s: str, /) OffsetDateTime[source]

Parse a popular version of the ISO 8601 datetime format.

Inverse of common_iso8601().

Note

While similar, this function behaves differently from from_canonical_format() or from_rfc3339().

Example

>>> OffsetDateTime.from_common_iso8601("2020-08-15T23:12:00+02:00")
OffsetDateTime(2020-08-15 23:12:00+02:00)
>>> # also valid:
>>> OffsetDateTime.from_common_iso8601("2020-08-15T23:12:00Z")
class whenever.ZonedDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, microsecond: int = 0, *, tz: str, disambiguate: Literal['compatible', 'earlier', 'later', 'raise'] = 'raise')[source]

A datetime associated with a IANA timezone ID. Useful for representing the local time bound to a specific location.

Example

>>> from whenever import ZonedDateTime
>>>
>>> # always at 11:00 in London, regardless of the offset
>>> changing_the_guard = ZonedDateTime(2024, 12, 8, hour=11, tz="Europe/London")
>>>
>>> # Explicitly resolve ambiguities when clocks are set backwards.
>>> night_shift = ZonedDateTime(2023, 10, 29, 1, 15, tz="Europe/London", disambiguate="later")
>>>
>>> # ZoneInfoNotFoundError: no such timezone
>>> ZonedDateTime(2024, 12, 8, hour=11, tz="invalid")
>>>
>>> # SkippedTime: 2:15 AM does not exist on this day
>>> ZonedDateTime(2023, 3, 26, 2, 15, tz="Europe/Amsterdam")

Disambiguation

The disambiguate argument controls how ambiguous datetimes are handled:

disambiguate

Behavior in case of ambiguity

"raise"

(default) Refuse to guess: raise AmbiguousTime or SkippedTime exception.

"earlier"

Choose the earlier of the two options

"later"

Choose the later of the two options

"compatible"

Choose “earlier” for backward transitions and “later” for forward transitions. This matches the behavior of other established libraries, and the industry standard RFC 5545. It corresponds to setting fold=0 in the standard library.

Warning

The canonical string format is:

YYYY-MM-DDTHH:MM:SS(.ffffff)±HH:MM(:SS(.ffffff))[TIMEZONE ID]

For example:

2020-08-15T23:12:00+01:00[Europe/London]

The offset is included to disambiguate cases where the same local time occurs twice due to DST transitions. If the offset is invalid for the system timezone, parsing will raise InvalidOffsetForZone.

This format is similar to those used by other languages, but it is not RFC 3339 or ISO 8601 compliant (these standards don’t support timezone IDs.) Use as_offset() first if you need RFC 3339 or ISO 8601 compliance.

classmethod now(tz: str) ZonedDateTime[source]

Create an instance from the current time in the given timezone

classmethod from_timestamp(i: float, /, tz: str) ZonedDateTime[source]

Create an instace from a UNIX timestamp.

property tz: str

The timezone ID

__add__(delta: DateTimeDelta | TimeDelta | DateDelta) ZonedDateTime[source]

Add an amount of time, accounting for timezone changes (e.g. DST).

Example

>>> d = ZonedDateTime(2023, 10, 28, 12, tz="Europe/Amsterdam", disambiguate="earlier")
>>> # adding exact units accounts for the DST transition
>>> d + hours(24)
ZonedDateTime(2023-10-29T11:00:00+01:00[Europe/Amsterdam])
>>> # adding date units keeps the same local time
>>> d + days(1)
ZonedDateTime(2023-10-29T12:00:00+01:00[Europe/Amsterdam])

Note

Addition of calendar units follows RFC 5545 (iCalendar) and the behavior of other established libraries:

  • Units are added from largest to smallest, truncating and/or wrapping after each step.

  • Adding days keeps the same local time. For example, scheduling a 11am event “a days later” will result in 11am local time the next day, even if there was a DST transition. Scheduling it exactly 24 hours would have resulted in a different local time.

  • If the resulting time is amgiuous after shifting the date, the “compatible” disambiguation is used. This means that for gaps, time is skipped forward.

__sub__(other: _AwareDateTime) TimeDelta[source]
__sub__(other: DateTimeDelta | TimeDelta | DateDelta) ZonedDateTime

Subtract another datetime or duration

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", disambiguate="later").ambiguous()
False
>>> ZonedDateTime(2023, 10, 29, 2, 15, tz="Europe/Amsterdam", disambiguate="later").ambiguous()
True
class whenever.LocalSystemDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, microsecond: int = 0, *, disambiguate: Literal['compatible', 'earlier', 'later', 'raise'] = 'raise')[source]

Represents a time in the system timezone. Unlike OffsetDateTime, it knows about the system timezone and its DST transitions.

Instances have the fixed offset of the system timezone at the time of initialization. The system timezone may change afterwards, but instances of this type will not reflect that change.

Example

>>> # 8:00 in the system timezone—Paris in this case
>>> alarm = LocalSystemDateTime(2024, 3, 31, hour=6)
LocalSystemDateTime(2024-03-31 06:00:00+02:00)
...
>>> # Conversion based on Paris' offset
>>> alarm.as_utc()
UTCDateTime(2024-03-31 04:00:00)
...
>>> # unlike OffsetDateTime, it knows about DST transitions
>>> bedtime = alarm - hours(8)
LocalSystemDateTime(2024-03-30 21:00:00+01:00)

Handling ambiguity

The system timezone may have ambiguous datetimes, such as during a DST transition. The disambiguate argument controls how ambiguous datetimes are handled:

disambiguate

Behavior in case of ambiguity

"raise"

(default) Refuse to guess: raise AmbiguousTime or SkippedTime exception.

"earlier"

Choose the earlier of the two options

"later"

Choose the later of the two options

"compatible"

Choose “earlier” for backward transitions and “later” for forward transitions. This matches the behavior of other established libraries, and the industry standard RFC 5545. It corresponds to setting fold=0 in the standard library.

Note

The canonical string format is:

YYYY-MM-DDTHH:MM:SS(.ffffff)±HH:MM(:SS(.ffffff))

This format is both RFC 3339 and ISO 8601 compliant.

Note

The underlying datetime object has a fixed timezone tzinfo.

classmethod now() LocalSystemDateTime[source]

Create an instance from the current time

classmethod from_timestamp(i: float, /) LocalSystemDateTime[source]

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

Example

>>> # assuming system timezone is America/New_York
>>> LocalSystemDateTime.from_timestamp(0)
LocalSystemDateTime(1969-12-31T19:00:00-05:00)
>>> LocalSystemDateTime.from_timestamp(1_123_000_000.45)
LocalSystemDateTime(2005-08-12T12:26:40.45-04:00)
>>> LocalSystemDateTime.from_timestamp(d.timestamp()) == d
True
property tzname: str

The name of the timezone as provided by the system, if known. Examples: "EST" or "CET".

If not set, returns an empty string.

Attention

This is different from the IANA timezone ID. For example, "Europe/Paris" is the IANA tz ID that observes "CET" in the winter and "CEST" in the summer.

__add__(delta: DateTimeDelta | TimeDelta | DateDelta) LocalSystemDateTime[source]

Add a duration to this datetime

Example

>>> # assuming system local TZ=Europe/Amsterdam
>>> d = LocalSystemDateTime(2023, 10, 28, 12, disambiguate="earlier")
>>> # adding exact units accounts for the DST transition
>>> d + hours(24)
LocalSystemDateTime(2023-10-29T11:00:00+01:00)
>>> # adding date units keeps the same local time
>>> d + days(1)
LocalSystemDateTime(2023-10-29T12:00:00+01:00)

Note

Addition of calendar units follows RFC 5545 (iCalendar) and the behavior of other established libraries:

  • Units are added from largest to smallest, truncating and/or wrapping after each step.

  • Adding days keeps the same local time. For example, scheduling a 11am event “a days later” will result in 11am local time the next day, even if there was a DST transition. Scheduling it exactly 24 hours would have resulted in a different local time.

  • If the resulting time is amgiuous after shifting the date, the “compatible” disambiguation is used. This means that for gaps, time is skipped forward.

__sub__(other: _AwareDateTime) TimeDelta[source]
__sub__(other: DateTimeDelta | TimeDelta | DateDelta) LocalSystemDateTime

Subtract another datetime or duration

Example

>>> d = LocalSystemDateTime(2020, 8, 15, hour=23, minute=12)
>>> d - hours(24) - seconds(5)
LocalSystemDateTime(2020-08-14 23:11:55)
class whenever.NaiveDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, microsecond: int = 0)[source]

A plain datetime without timezone or offset.

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.

Note

The canonical string format is:

YYYY-MM-DDTHH:MM:SS(.fff(fff))

This format is ISO 8601 compliant, but not RFC 3339 compliant, because this requires a UTC offset.

__eq__(other: object) bool[source]

Compare objects for equality. Only ever equal to other NaiveDateTime 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

>>> NaiveDateTime(2020, 8, 15, 23) == NaiveDateTime(2020, 8, 15, 23)
True
>>> NaiveDateTime(2020, 8, 15, 23, 1) == NaiveDateTime(2020, 8, 15, 23)
False
>>> NaiveDateTime(2020, 8, 15) == UTCDateTime(2020, 8, 15)
False  # Use mypy's --strict-equality flag to detect this.
__add__(delta: DateTimeDelta | TimeDelta | DateDelta) NaiveDateTime[source]

Add a duration to this datetime

Example

>>> d = NaiveDateTime(2020, 8, 15, hour=23, minute=12)
>>> d + hours(24) + seconds(5)
NaiveDateTime(2020-08-16 23:12:05)
>>> d + years(3) + months(2) + days(1)
NaiveDateTime(2023-10-16 23:12:00)
__sub__(other: NaiveDateTime) TimeDelta[source]
__sub__(other: DateTimeDelta | TimeDelta | DateDelta) NaiveDateTime

Subtract another datetime or time amount

Example

>>> d = NaiveDateTime(2020, 8, 15, hour=23, minute=12)
>>> d - hours(24) - seconds(5)
NaiveDateTime(2020-08-14 23:11:55)
>>> d - NaiveDateTime(2020, 8, 14)
TimeDelta(47:12:00)
>>> d - years(3) - months(2) - days(1) - minutes(5)
NaiveDateTime(2017-06-14 23:07:00)
classmethod strptime(s: str, /, fmt: str) NaiveDateTime[source]

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

Example

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

Note

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

assume_utc() UTCDateTime[source]

Assume the datetime is in UTC, creating a UTCDateTime instance.

Example

>>> NaiveDateTime(2020, 8, 15, 23, 12).assume_utc()
UTCDateTime(2020-08-15 23:12:00Z)
assume_offset(offset: int | TimeDelta, /) OffsetDateTime[source]

Assume the datetime is in the given offset, creating a OffsetDateTime instance.

Example

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

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

Example

>>> NaiveDateTime(2020, 8, 15, 23, 12).assume_zoned("Europe/Amsterdam")
ZonedDateTime(2020-08-15 23:12:00+02:00[Europe/Amsterdam])
assume_local(disambiguate: Literal['compatible', 'earlier', 'later', 'raise'] = 'raise') LocalSystemDateTime[source]

Assume the datetime is in the system timezone, creating a LocalSystemDateTime instance.

Example

>>> # assuming system timezone is America/New_York
>>> NaiveDateTime(2020, 8, 15, 23, 12).assume_local()
LocalSystemDateTime(2020-08-15 23:12:00-04:00)
common_iso8601() str[source]

Format in the commonly used ISO 8601 format.

Inverse of from_common_iso8601().

Example

>>> NaiveDateTime(2020, 8, 15, 23, 12).common_iso8601()
'2020-08-15T23:12:00'
classmethod from_common_iso8601(s: str, /) NaiveDateTime[source]

Parse from the commonly used ISO 8601 format YYYY-MM-DDTHH:MM:SS, where seconds may be fractional.

Inverse of common_iso8601().

Example

>>> NaiveDateTime.from_common_iso8601("2020-08-15T23:12:00")
NaiveDateTime(2020-08-15 23:12:00)

Deltas

whenever.years(i: int, /) DateDelta[source]

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

whenever.months(i: int, /) DateDelta[source]

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

whenever.weeks(i: int, /) DateDelta[source]

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

whenever.days(i: int, /) DateDelta[source]

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

whenever.hours(i: float, /) TimeDelta[source]

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

whenever.minutes(i: float, /) TimeDelta[source]

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

whenever.seconds(i: float, /) TimeDelta[source]

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

whenever.microseconds(i: int, /) TimeDelta[source]

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

class whenever.TimeDelta(*, hours: float = 0, minutes: float = 0, seconds: float = 0, microseconds: int = 0)[source]

A duration consisting of a precise time: hours, minutes, (micro)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
ZERO: ClassVar[TimeDelta] = TimeDelta(00:00:00)

A delta of zero

in_hours() float[source]

The total size in hours

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d.in_hours()
1.5
in_minutes() float[source]

The total size in minutes

Example

>>> d = TimeDelta(hours=1, minutes=30, seconds=30)
>>> d.in_minutes()
90.5
in_seconds() float[source]

The total size in seconds

Example

>>> d = TimeDelta(minutes=2, seconds=1, microseconds=500_000)
>>> d.in_seconds()
121.5
in_microseconds() int[source]

The total size in microseconds

>>> d = TimeDelta(seconds=2, microseconds=50)
>>> d.in_microseconds()
2_000_050
__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.

__bool__() bool[source]

True if the value is non-zero

Example

>>> bool(TimeDelta())
False
>>> bool(TimeDelta(minutes=1))
True
__add__(other: TimeDelta) TimeDelta[source]

Add two deltas together

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d + TimeDelta(minutes=30)
TimeDelta(02:00:00)
__sub__(other: TimeDelta) TimeDelta[source]

Subtract two deltas

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d - TimeDelta(minutes=30)
TimeDelta(01:00:00)
__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)
__truediv__(other: float) TimeDelta[source]
__truediv__(other: TimeDelta) float

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
__abs__() TimeDelta[source]

The absolute value

Example

>>> d = TimeDelta(hours=-1, minutes=-30)
>>> abs(d)
TimeDelta(01:30:00)
canonical_format() str[source]

Format the delta in the canonical string format.

The format is:

HH:MM:SS(.ffffff)

For example:

01:24:45.0089
classmethod from_canonical_format(s: str, /) TimeDelta[source]

Create from the canonical string representation.

Inverse of canonical_format()

Example

>>> TimeDelta.from_canonical_format("01:30:00")
TimeDelta(01:30:00)
Raises:

ValueError – If the string does not match this exact format.

common_iso8601() 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 from_common_iso8601()

Example

>>> TimeDelta(hours=1, minutes=30).common_iso8601()
'PT1H30M'
classmethod from_common_iso8601(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 common_iso8601()

Example

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

Note

Any duration with a non-zero date part is considered invalid. P0D is valid, but P1DT1H is not.

py_timedelta() timedelta[source]

Convert to a timedelta

Inverse of from_py_timedelta()

Example

>>> d = TimeDelta(hours=1, minutes=30)
>>> d.py_timedelta()
timedelta(seconds=5400)
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)
as_tuple() tuple[int, int, int, int][source]

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

Example

>>> d = TimeDelta(hours=1, minutes=30, microseconds=5_000_090)
>>> d.as_tuple()
(1, 30, 5, 90)
class whenever.DateDelta(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0)[source]

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

ZERO: ClassVar[DateDelta] = DateDelta(P0D)

A delta of zero

property years: int
property months: int
property weeks: int
property days: int
__eq__(other: object) bool[source]

Compare for equality of all fields

Note

DateDeltas are equal if they have the same values for all fields. No normalization is done, so “7 days” is not equal to “1 week”.

Example

>>> p = DateDelta(weeks=1, days=11, years=0)
>>> p == DateDelta(weeks=1, days=11)
True
>>> # same delta, but different field values
>>> p == DateDelta(weeks=2, days=4)
False
__bool__() bool[source]

True if any field is non-zero

Example

>>> bool(DateDelta())
False
>>> bool(DateDelta(days=-1))
True
replace(**kwargs) DateDelta[source]

Create a new instance with the given fields replaced.

Example

>>> p = DateDelta(years=1, months=2)
>>> p.replace(years=2)
DateDelta(P2Y2M)
__neg__() DateDelta[source]

Negate each field

Example

>>> p = DateDelta(weeks=2, days=-3)
>>> -p
DateDelta(P-2W3DT)
__mul__(other: int) DateDelta[source]

Multiply each field by a round number

Example

>>> p = DateDelta(years=1, weeks=2)
>>> p * 2
DateDelta(P2Y4W)
__add__(other: DateDelta) DateDelta[source]
__add__(other: TimeDelta) DateTimeDelta

Add the fields of another delta to this one

Example

>>> p = DateDelta(weeks=2, months=1)
>>> p + DateDelta(weeks=1, days=-4)
DateDelta(P1M3W-4D)
__sub__(other: DateDelta) DateDelta[source]
__sub__(other: TimeDelta) DateTimeDelta

Subtract the fields of another delta from this one

Example

>>> p = DateDelta(weeks=2, days=3)
>>> p - DateDelta(days=2)
DateDelta(P2W1D)
__abs__() DateDelta[source]

The absolute value of each field

Example

>>> p = DateDelta(weeks=-2, days=3)
>>> abs(p)
DateDelta(P2W3D)
canonical_format() str[source]

The delta in canonical format.

The canonical string format is:

P(nY)(nM)(nW)(nD)

For example:

P1D
P2M
P1Y2M-3W4D

Example

>>> p = DateDelta(years=1, months=2, weeks=3, days=11)
>>> p.canonical_format()
'P1Y2M3W11D'
>>> DateDelta().canonical_format()
'P0D'
classmethod from_canonical_format(s: str, /) DateDelta[source]

Create from the canonical string representation.

Inverse of canonical_format()

Example

>>> DateDelta.from_canonical_format("1Y2M-3W4D")
DateDelta(P1Y2M-3W4D)
common_iso8601() 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 from_common_iso8601()

Example

>>> DateDelta(weeks=1, days=11).common_iso8601()
'P1W11D'
classmethod from_common_iso8601(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 common_iso8601().

Example

>>> DateDelta.from_common_iso8601("P1W11D")
DateDelta(P1W11D)

Note

Any duration with a non-zero time part is considered invalid. PT0S is valid, but P3DT1H is not.

as_tuple() tuple[int, int, int, int][source]

Convert to a tuple of (years, months, weeks, days)

Example

>>> p = DateDelta(weeks=2, days=3)
>>> p.as_tuple()
(0, 0, 2, 3)
class whenever.DateTimeDelta(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0, hours: float = 0, minutes: float = 0, seconds: float = 0, microseconds: int = 0)[source]

A duration with both a date and time component.

ZERO: ClassVar[DateTimeDelta] = DateTimeDelta(P0D)

A delta of zero

property date_part: DateDelta
property time_part: TimeDelta
__eq__(other: object) bool[source]

Compare for equality

Example

>>> d = DateTimeDelta(
...     weeks=1,
...     days=11,
...     hours=4,
... )
>>> d == DateTimeDelta(
...     weeks=1,
...     days=11,
...     minutes=4 * 60,  # normalized
... )
True
>>> d == DateTimeDelta(
...     weeks=2,
...     days=4,  # not normalized
...     hours=4,
... )
False
__bool__() bool[source]

True if any field is non-zero

Example

>>> bool(DateTimeDelta())
False
>>> bool(DateTimeDelta(minutes=1))
True
__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)
__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(P-2M1W8DT2H30M)
__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(weeks=1, days=-11, hours=4)
>>> -d
DateTimeDelta(P-1W11DT-4H)
__abs__() DateTimeDelta[source]

The absolute value of the delta

Example

>>> d = DateTimeDelta(weeks=1, days=-11, hours=4)
>>> abs(d)
DateTimeDelta(P1W11DT4H)
canonical_format() str[source]

The delta in canonical format.

Example

>>> d = DateTimeDelta(
...     weeks=1,
...     days=11,
...     hours=4,
... )
>>> d.canonical_format()
'P1W11DT4H'
classmethod from_canonical_format(s: str, /) DateTimeDelta[source]

Create from the canonical string representation. Inverse of canonical_format()

Examples:

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

Example

>>> DateTimeDelta.from_canonical_format("P1W11DT4H")
DateTimeDelta(weeks=1, days=11, hours=4)
Raises:

ValueError – If the string does not match this exact format.

common_iso8601() 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.

Example

>>> DateTimeDelta(weeks=1, days=-11, hours=4).common_iso8601()
'P1W-11DT4H'
classmethod from_common_iso8601(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.

Example

>>> DateTimeDelta.from_common_iso8601("-P1W11DT4H")
DateTimeDelta(P-1W-11DT-4H)
as_tuple() tuple[int, int, int, int, int, int, int, int][source]

Convert to a tuple of (years, months, weeks, days, hours, minutes, seconds, microseconds)

Example

>>> d = DateTimeDelta(weeks=1, days=11, hours=4)
>>> d.as_tuple()
(0, 0, 1, 11, 4, 0, 0, 0)

Date and time components

class whenever.Date(year: int, month: int, day: int)[source]

A date without a time component

Example

>>> d = Date(2021, 1, 2)
Date(2021-01-02)
__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
__lt__(other: Date) bool[source]

Return self<value.

__le__(other: Date) bool[source]

Return self<=value.

__gt__(other: Date) bool[source]

Return self>value.

__ge__(other: Date) bool[source]

Return self>=value.

py_date() date[source]

Get the underlying date object

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)
add(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0) Date[source]

Add a components to a date.

Components are added from largest to smallest. Trucation and wrapping is done after each step.

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)
__add__(p: DateDelta) Date[source]

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

subtract(*, years: int = 0, months: int = 0, weeks: int = 0, days: int = 0) Date[source]

Subtract a components from a date.

Components are subtracted from largest to smallest. Trucation and wrapping is done after each step.

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)
__sub__(d: DateDelta) Date[source]
__sub__(d: Date) DateDelta

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 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(P-9M)
day_of_week() int[source]

The day of the week, where 1 is Monday and 7 is Sunday

Warning

This method uses the ISO definition of the week, in contrast to the weekday() method.

Example

>>> from whenever import SATURDAY
>>> Date(2021, 1, 2).day_of_week()
6
>>> Date(2021, 1, 2).day_of_week() == SATURDAY
True
at(t: Time, /) NaiveDateTime[source]

Combine a date with a time to create a datetime

Example

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

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

canonical_format() str[source]

The date in canonical format.

Example

>>> d = Date(2021, 1, 2)
>>> d.canonical_format()
'2021-01-02'
classmethod from_canonical_format(s: str, /) Date[source]

Create from the canonical string representation.

Inverse of canonical_format()

Example

>>> Date.from_canonical_format("2021-01-02")
Date(2021-01-02)
common_iso8601() str[source]

Format as the common ISO 8601 date format.

Inverse of from_common_iso8601(). Equivalent to canonical_format().

Example

>>> Date(2021, 1, 2).common_iso8601()
'2021-01-02'
classmethod from_common_iso8601(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 common_iso8601(). Equivalent to from_canonical_format().

Example

>>> Date.from_common_iso8601("2021-01-02")
Date(2021-01-02)
class whenever.Time(hour: int = 0, minute: int = 0, second: int = 0, microsecond: int = 0)[source]

Time of day without a date component

Example

>>> t = Time(12, 30, 0)
Time(12:30:00)

Canonical format

The canonical format is:

HH:MM:SS(.ffffff)

For example:

12:30:11.004
MIDNIGHT: ClassVar[Time] = Time(00:00:00)

The time at midnight

NOON: ClassVar[Time] = Time(12:00:00)

The time at noon

MAX: ClassVar[Time] = Time(23:59:59.999999)

The maximum time, just before midnight

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)

Raises ValueError if the time is not naive or has fold=1.

__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
__lt__(other: Time) bool[source]

Return self<value.

__le__(other: Time) bool[source]

Return self<=value.

__gt__(other: Time) bool[source]

Return self>value.

__ge__(other: Time) bool[source]

Return self>=value.

on(d: Date, /) NaiveDateTime[source]

Combine a time with a date to create a datetime

Example

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

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

canonical_format() str[source]

The time in canonical format.

Example

>>> t = Time(12, 30, 0)
>>> t.canonical_format()
'12:30:00'
classmethod from_canonical_format(s: str, /) Time[source]

Create from the canonical string representation.

Inverse of canonical_format()

Example

>>> Time.from_canonical_format("12:30:00")
Time(12:30:00)
Raises:

ValueError – If the string does not match this exact format.

common_iso8601() str[source]

Format as the common ISO 8601 time format.

Inverse of from_common_iso8601(). Equivalent to canonical_format().

Example

>>> Time(12, 30, 0).common_iso8601()
'12:30:00'
classmethod from_common_iso8601(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 common_iso8601(). Equivalent to from_canonical_format().

Example

>>> Time.from_common_iso8601("12:30:00")
Time(12:30:00)

Exceptions

exception whenever.AmbiguousTime[source]

A datetime is unexpectedly ambiguous

exception whenever.SkippedTime[source]

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

exception whenever.InvalidOffsetForZone[source]

A string has an invalid offset for the given zone