ItemizedDateDelta

final class whenever.ItemizedDateDelta(iso_string: str, /)[source]
final class whenever.ItemizedDateDelta(*, years: int = ..., months: int = ..., weeks: int = ..., days: int = ...)

A date duration that preserves the exact fields it was created with. It closely models the ISO 8601 duration format for date-only durations.

>>> d = ItemizedDateDelta(years=2, weeks=3)
ItemizedDateDelta("P2Y3W")
>>> d = ItemizedDateDelta("P22W")
>>> str(d)
'P22W'

It behaves like a mapping where the keys are the unit names and the values are the amounts. Items are ordered from largest to smallest unit.

>>> d['weeks']
22
>>> d.get('days')
None
>>> dict(d)
{"years": 2, "weeks": 3}
>>> list(d.keys())
["years", "weeks"]
>>> years, weeks = d.values()
(2, 3)

ItemizedDateDelta also supports other dictionary-like operations:

>>> "days" in d  # check for presence of a field
False
>>> len(d)  # number of fields set
2

Zero values are considered distinct from “missing” values:

>>> d2 = ItemizedDateDelta(years=2, weeks=3, days=0)
>>> dict(d2)
{"years": 2, "weeks": 3, "days": 0}

Additionally, no normalization is performed. Months are not rolled into years, weeks into days, etc.

>>> d3 = ItemizedDateDelta(months=24, days=100)
ItemizedDateDelta("P24m100d")

Empty durations are not allowed. At least one field must be set (but it can be zero):

>>> ItemizedDateDelta()
ValueError: At least one field must be set
>>> ItemizedDateDelta(days=0)
ItemizedDateDelta("P0d")

Negative durations are supported, but all fields must have the same sign:

>>> d4 = ItemizedDateDelta(years=-1, weeks=-2, days=0)
ItemizedDateDelta("-P1y2w0d")
>>> ItemizedDateDelta(years=1, days=-3)
ValueError: All fields must have the same sign

Note

Unlike DateDelta, ItemizedDateDelta does not normalize its fields. This means that ItemizedDateDelta(months=14) and ItemizedDateDelta(years=1, months=2) are considered different values. To convert to a normalized form, use in_units(). See also the delta documentation.

classmethod parse_iso(s: str, /) ItemizedDateDelta[source]

Parse the popular interpretation of the ISO 8601 duration format. Inverse of format_iso()

>>> ItemizedDateDelta.parse_iso("-P1W11D")
ItemizedDateDelta("-P1w11d")

You can also use the constructor ItemizedDateDelta(s) which is equivalent to ItemizedDateDelta.parse_iso(s).

Note

Does not parse all possible ISO 8601 durations. In particular, it doesn’t allow fractional values. See here for more information.

__abs__() ItemizedDateDelta[source]

If the contents are negative, return the positive version

>>> d = ItemizedDateDelta(weeks=-2, days=-3)
>>> abs(d)
ItemizedDateDelta("P2w3d")
__bool__() bool[source]

An ItemizedDateDelta is considered False if its sign is 0.

>>> d = ItemizedDateDelta(weeks=0)
>>> bool(d)
False
>>> d = ItemizedDateDelta(weeks=1)
>>> bool(d)
True
__contains__(key: object) bool[source]

Check if a specific field is set.

>>> d = ItemizedDateDelta(weeks=1, days=0)
>>> "weeks" in d
True
>>> "days" in d
True
>>> "months" in d
False
__eq__(other: object) bool[source]

Compare each field for equality, under the following rules:

  • No normalization is performed. 12 months is not equal to 1 year, etc.

  • Zero values are considered equivalent to missing values.

If you want strict equality (including presence of fields), use exact_eq().

>>> d = ItemizedDateDelta(weeks=2, days=3)
>>> d == ItemizedDateDelta(weeks=2, days=3, months=0)
True
>>> d == ItemizedDateDelta(weeks=2, days=4)
False
__getitem__(key: DateDeltaUnitStr) int[source]

Get the value of a specific field by name.

>>> d = ItemizedDateDelta(weeks=1, days=0)
>>> d["weeks"]
1
>>> d["days"]
0
>>> d["years"]
KeyError: 'years'
__iter__() Iterator[TypeAliasForwardRef('DateDeltaUnitStr')][source]

Iterate over all unit names for fields that are set, ordered from largest to smallest unit.

__len__() int[source]

Get the number of fields that are set.

>>> d = ItemizedDateDelta(weeks=1, days=0)
>>> len(d)
2
__neg__() ItemizedDateDelta[source]

Invert the sign of the contents

>>> d = ItemizedDateDelta(weeks=2, days=3)
>>> -d
ItemizedDateDelta("-P2w3d")
>>> --d
ItemizedDateDelta("P2w3d")
__str__(*, lowercase_units: bool = False) str

Convert to the canionical ISO 8601 string representation:

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

You can also use str(d) which is equivalent to d.format_iso().

Inverse of parse_iso().

>>> d = ItemizedDateDelta(weeks=1, days=11)
>>> d.format_iso()
'P1W11D'

Note

Negative durations are prefixed with a minus sign, which is not part of the ISO 8601 standard, but is a common extension. See here for more information.

add(
other: ItemizedDateDelta,
/,
*,
relative_to: Date,
in_units: Sequence[TypeAliasForwardRef('DateDeltaUnitStr')],
round_mode: RoundModeStr = 'trunc',
round_increment: int = 1,
) ItemizedDateDelta[source]
add(
*,
years: int = ...,
months: int = ...,
weeks: int = ...,
days: int = ...,
relative_to: Date,
in_units: Sequence[TypeAliasForwardRef('DateDeltaUnitStr')],
round_mode: RoundModeStr = 'trunc',
round_increment: int = 1,
) ItemizedDateDelta

Add time to this delta, returning a new delta

exact_eq(other: ItemizedDateDelta, /) bool[source]

Check for strict equality. All fields and their presence must match.

>>> d = ItemizedDateDelta(weeks=2, days=3)
>>> d == ItemizedDateDelta(weeks=2, days=3)
True
>>> d == ItemizedDateDelta(weeks=2, days=3, months=0)
True
>>> d.exact_eq(ItemizedDateDelta(weeks=2, days=3, months=0))
False
format_iso(*, lowercase_units: bool = False) str[source]

Convert to the canionical ISO 8601 string representation:

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

You can also use str(d) which is equivalent to d.format_iso().

Inverse of parse_iso().

>>> d = ItemizedDateDelta(weeks=1, days=11)
>>> d.format_iso()
'P1W11D'

Note

Negative durations are prefixed with a minus sign, which is not part of the ISO 8601 standard, but is a common extension. See here for more information.

get(key: DateDeltaUnitStr, /) int | None[source]
get(key: DateDeltaUnitStr, default: int, /) int

Get the value of a specific field by name, or return default if not set.

Part of the mapping protocol

in_units(
units: Sequence[TypeAliasForwardRef('DateDeltaUnitStr')],
/,
*,
relative_to: Date,
round_mode: RoundModeStr = 'trunc',
round_increment: int = 1,
) ItemizedDateDelta[source]

Convert this delta into the specified units. A relative_to date is required to resolve variable-length units (years and months).

>>> d = ItemizedDateDelta(years=1, months=8)
>>> d.in_units(["weeks", "days"], relative_to=Date(2020, 6, 30))
ItemizedDateDelta("P86w6d")
items() ItemsView[TypeAliasForwardRef('DateDeltaUnitStr'), int][source]

Return all defined fields as (unit, value) pairs ordered from largest to smallest unit.

>>> d = ItemizedDateDelta(years=3, days=12, months=0)
>>> list(d.items())
[('years', 3), ('months', 0), ('days', 12)]
keys() KeysView[TypeAliasForwardRef('DateDeltaUnitStr')][source]

The names of all defined fields, ordered from largest to smallest unit.

Part of the mapping protocol

replace(
*,
years: int | None = ...,
months: int | None = ...,
weeks: int | None = ...,
days: int | None = ...,
) ItemizedDateDelta[source]

Return a new delta with specific fields replaced. Fields set to None will be removed.

All normal validation rules apply.

>>> d = ItemizedDateDelta(years=1, months=2, weeks=3)
>>> d.replace(months=None, weeks=4)
ItemizedDateDelta("P1y4w")
sign() Literal[1, 0, -1][source]

The sign of the delta, whether it’s positive, negative, or zero.

>>> ItemizedDateDelta(weeks=2).sign()
1
>>> ItemizedDateDelta(days=-3).sign()
-1
>>> ItemizedDateDelta(weeks=0).sign()
0
subtract(
other: ItemizedDateDelta,
/,
*,
relative_to: Date,
in_units: Sequence[TypeAliasForwardRef('DateDeltaUnitStr')],
round_mode: RoundModeStr = 'trunc',
round_increment: int = 1,
) ItemizedDateDelta[source]
subtract(
*,
years: int = ...,
months: int = ...,
weeks: int = ...,
days: int = ...,
relative_to: Date,
in_units: Sequence[TypeAliasForwardRef('DateDeltaUnitStr')],
round_mode: RoundModeStr = 'trunc',
round_increment: int = 1,
) ItemizedDateDelta

Subtract time from this delta, returning a new delta

total(unit: DateDeltaUnitStr, /, *, relative_to: Date) float[source]

Return the total duration expressed in the specified unit as a float

>>> ItemizedDateDelta(years=1, months=6).total("months", relative_to=Date(2020, 1, 31))
18.0
>>> ItemizedDateDelta(days=1000).total("years", relative_to=Date(2020, 4, 10))
2.73972602739726
values() ValuesView[int][source]

Return all defined field values, in order of largest to smallest unit.

>>> d = ItemizedDateDelta(years=3, days=12, months=0)
>>> years, months, days = d.values()
(3, 0, 12)
>>> list(d.values())
[3, 0, 12]