PlainDateTime

final class whenever.PlainDateTime(iso_string: str, /)[source]
final class whenever.PlainDateTime(py_dt: datetime, /)
final class whenever.PlainDateTime(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, *, nanosecond: int = 0)

A date and time-of-day without any timezone information.

Represents “wall clock” time as people observe it locally. It can’t be mixed with exact-time types (e.g. Instant, ZonedDateTime) without explicitly assuming a timezone or offset.

>>> PlainDateTime(2024, 3, 10, 15, 30)
PlainDateTime("2024-03-10 15:30:00")

Can also be constructed from an ISO 8601 string or a standard library datetime:

>>> PlainDateTime("2024-03-10T15:30:00")
PlainDateTime("2024-03-10 15:30:00")

Convert to an exact time type by supplying a timezone or offset:

>>> dt = PlainDateTime(2024, 3, 10, 15, 30)
>>> dt.assume_tz("Europe/Amsterdam")
ZonedDateTime("2024-03-10 15:30:00+01:00[Europe/Amsterdam]")
>>> dt.assume_fixed_offset(5)
OffsetDateTime("2024-03-10 15:30:00+05:00")

When to use this type:

  • You need to express a date and time as it would appear on a wall clock, independent of timezone.

  • You receive a datetime without timezone information and need to represent this lack of information in the type system.

  • You’re working in a context where timezones and DST transitions truly don’t apply (e.g. a simulation).

classmethod from_py_datetime(d: datetime, /) _T

Create an instance from a datetime object.

Deprecated since version 0.10.0: Use the constructor instead (e.g. Instant(d), ZonedDateTime(d), etc.)

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.

classmethod parse(s: str, /, *, format: str) PlainDateTime[source]

Parse a plain datetime from a custom pattern string.

See Pattern format for details.

>>> PlainDateTime.parse("2024-03-15 14:30", format="YYYY-MM-DD hh:mm")
PlainDateTime("2024-03-15 14:30:00")
classmethod parse_iso(s: str, /) PlainDateTime[source]

Parse the popular ISO format YYYY-MM-DDTHH:MM:SS

The inverse of the format_iso() method.

>>> PlainDateTime.parse_iso("2020-08-15T23:12:00")
PlainDateTime("2020-08-15 23:12:00")
classmethod parse_strptime(s: str, /, *, format: str) PlainDateTime[source]

Parse a plain datetime using the standard library strptime() method.

Deprecated since version 0.10.0: Use parse() with a pattern string instead, or use PlainDateTime(datetime.strptime(...)).

__add__(delta: DateDelta | TimeDelta) PlainDateTime[source]

Add a delta to this datetime.

Warning

Adding exact time units (a TimeDelta) to a PlainDateTime does not account for timezone transitions that may occur in the interval. Use .assume_tz('<tz>') + delta if you know the timezone. Suppress with the ignore_timezone_unaware_arithmetic_warning() context manager; Python’s standard warning filters also apply.

__eq__(other: object) bool[source]

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

>>> PlainDateTime(2020, 8, 15, 23) == PlainDateTime(2020, 8, 15, 23)
True
>>> PlainDateTime(2020, 8, 15, 23, 1) == PlainDateTime(2020, 8, 15, 23)
False
>>> PlainDateTime(2020, 8, 15) == Instant.from_utc(2020, 8, 15)
False  # Use mypy's --strict-equality flag to detect this.
__format__(spec: str, /) str[source]

Default object formatter.

Return str(self) if format_spec is empty. Raise TypeError otherwise.

__ge__(other: PlainDateTime) bool[source]

Return self>=value.

__gt__(other: PlainDateTime) bool[source]

Return self>value.

__le__(other: PlainDateTime) bool[source]

Return self<=value.

__lt__(other: PlainDateTime) bool[source]

Return self<value.

__str__() str

Return str(self).

__sub__(other: PlainDateTime) TimeDelta[source]
__sub__(other: TimeDelta | DateDelta) PlainDateTime

Subtract a delta or calculate the duration to another plain datetime.

Warning

Subtracting a TimeDelta or measuring the difference between two PlainDateTime values does not account for timezone transitions that may occur in the interval. Use assume_tz() to convert to a ZonedDateTime first for accurate results. Suppress with the ignore_timezone_unaware_arithmetic_warning() context manager; Python’s standard warning filters also apply.

add(
d: DateTimeDelta | TimeDelta | DateDelta | ItemizedDelta | ItemizedDateDelta,
/,
*,
ignore_dst: bool = ...,
) PlainDateTime[source]
add(
*,
years: int = ...,
months: int = ...,
weeks: int = ...,
days: int = ...,
hours: float = ...,
minutes: float = ...,
seconds: float = ...,
milliseconds: float = ...,
microseconds: float = ...,
nanoseconds: int = ...,
ignore_dst: bool = ...,
) PlainDateTime

Add a time amount to this datetime.

Warning

Adding exact time units (e.g. hours, seconds) to a PlainDateTime does not account for timezone transitions that may occur in the interval. Use .assume_tz('<tz>') + delta if you know the timezone. Suppress with the ignore_timezone_unaware_arithmetic_warning() context manager; Python’s standard warning filters also apply.

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

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

>>> PlainDateTime(2020, 8, 15, 23, 12).assume_fixed_offset(+2)
OffsetDateTime("2020-08-15 23:12:00+02:00")
assume_system_tz(disambiguate: DisambiguateStr = 'compatible') ZonedDateTime[source]

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

Note

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

>>> d = PlainDateTime(2020, 8, 15, 23, 12)
>>> # assuming system timezone is America/New_York
>>> d.assume_system_tz(disambiguate="raise")
ZonedDateTime("2020-08-15 23:12:00-04:00[America/New_York]")
assume_tz(tz: str, /, disambiguate: DisambiguateStr = 'compatible') ZonedDateTime[source]

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

Note

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

>>> d = PlainDateTime(2020, 8, 15, 23, 12)
>>> d.assume_tz("Europe/Amsterdam", disambiguate="raise")
ZonedDateTime("2020-08-15 23:12:00+02:00[Europe/Amsterdam]")
assume_utc() Instant[source]

Assume the datetime is in UTC, creating an Instant.

>>> PlainDateTime(2020, 8, 15, 23, 12).assume_utc()
Instant("2020-08-15 23:12:00Z")
date() Date

The date part of the datetime

>>> d = PlaineDateTime("2020-01-02 03:04:05")
>>> 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")
ZonedDateTime("2021-01-02T03:04:05+00:00[Europe/London]")
difference(other: PlainDateTime, /, *, ignore_dst: bool = ...) TimeDelta[source]

Calculate the difference between two times without a timezone.

Deprecated since version 0.10.0: The difference() method is deprecated, use the subtraction operator or since() method instead.

format(pattern: str, /) str[source]

Format as a custom pattern string.

Also available via f"{dt:YYYY-MM-DD hh:mm}" (Python’s __format__ protocol), where an empty spec falls back to __str__().

See Pattern format for details.

>>> PlainDateTime(2024, 3, 15, 14, 30).format("YYYY-MM-DD hh:mm")
'2024-03-15 14:30'
format_iso(
*,
unit: Literal['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond', 'auto'] = 'auto',
basic: bool = False,
sep: Literal['T', ' '] = 'T',
) str[source]

Convert to the popular ISO format YYYY-MM-DDTHH:MM:SS

The inverse of the parse_iso() method.

py_datetime() datetime

Convert to a standard library datetime

Deprecated since version 0.10.0: Use to_stdlib() instead.

replace(
*,
year: int = ...,
month: int = ...,
day: int = ...,
hour: int = ...,
minute: int = ...,
second: int = ...,
nanosecond: int = ...,
) PlainDateTime[source]

Construct a new instance with the given fields replaced.

replace_date(d: Date, /) PlainDateTime[source]

Construct a new instance with the date replaced.

replace_time(t: Time, /) PlainDateTime[source]

Construct a new instance with the time replaced.

round(
unit: Literal['day', 'hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'] | TimeDelta = 'second',
/,
*,
increment: int = 1,
mode: RoundModeStr = 'half_even',
) PlainDateTime[source]

Round the datetime to the specified unit and increment, or to a multiple of a TimeDelta. Different rounding modes are available.

>>> d = PlainDateTime(2020, 8, 15, 23, 24, 18)
>>> d.round("day")
PlainDateTime("2020-08-16 00:00:00")
>>> d.round("minute", increment=15, mode="floor")
PlainDateTime("2020-08-15 23:15:00")

Note

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

since(b: PlainDateTime, /, *, total: DeltaUnitStr) float[source]
since(
b: PlainDateTime,
/,
*,
in_units: Sequence[TypeAliasForwardRef('DeltaUnitStr')],
round_mode: RoundModeStr = ...,
round_increment: int = ...,
) ItemizedDelta

Calculate the duration since another PlainDateTime, in terms of the specified units.

>>> d1 = PlainDateTime(2020, 8, 15, 23, 12)
>>> d2 = PlainDateTime(2020, 8, 14, 22)
>>> d1.since(d2, in_units=["hours", "minutes"],
...          round_increment=15,
...          round_mode="ceil")
ItemizedDelta("PT25h15m")
subtract(
d: DateTimeDelta | TimeDelta | DateDelta | ItemizedDelta | ItemizedDateDelta,
/,
*,
ignore_dst: bool = ...,
) PlainDateTime[source]
subtract(
*,
years: int = ...,
months: int = ...,
weeks: int = ...,
days: int = ...,
hours: float = ...,
minutes: float = ...,
seconds: float = ...,
milliseconds: float = ...,
microseconds: float = ...,
nanoseconds: int = ...,
ignore_dst: bool = ...,
) PlainDateTime

Subtract a time amount from this datetime.

See add() for more information.

time() Time

The time-of-day part of the datetime

>>> d = 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")
ZonedDateTime("2021-01-02T03:04:05+01:00[Europe/Paris]")
to_stdlib() datetime

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.

  • For ZonedDateTime linked to a system timezone without a IANA timezone ID, the returned Python datetime will have a fixed offset (timezone tzinfo)

until(b: PlainDateTime, /, *, total: DeltaUnitStr) float[source]
until(
b: PlainDateTime,
/,
*,
in_units: Sequence[TypeAliasForwardRef('DeltaUnitStr')],
round_mode: RoundModeStr = ...,
round_increment: int = ...,
) ItemizedDelta

Inverse of the since() method. See since() for more information.

MAX: ClassVar[PlainDateTime] = PlainDateTime("9999-12-31 23:59:59.999999999")

The maximum representable value of this type.

MIN: ClassVar[PlainDateTime] = PlainDateTime("0001-01-01 00:00:00")

The minimum representable value of this type.

property day: int

The day component of the datetime

property hour: int

The hour component of the datetime

property minute: int

The minute component of the datetime

property month: int

The month component of the datetime

property nanosecond: int

The nanosecond component of the datetime

property second: int

The second component of the datetime

property year: int

The year component of the datetime