Dates and time
rigour.dates
Compare prefix dates without pretending they are exact instants.
A prefix date such as 2026 or 2026-06 represents an interval, rather
than the first instant of that year or month. Use the string wrappers for
one-off comparisons, or parse a DateInterval once
when comparing the same value repeatedly.
Age and recency checks use the same comparisons with a shifted reference:
DateInterval
dataclass
Represent every possible instant described by an imprecise date.
Use this parsed form when applying multiple comparisons to the same prefix
date. Both bounds are timezone-aware UTC datetimes and end is exclusive.
Attributes:
| Name | Type | Description |
|---|---|---|
start |
datetime
|
Earliest instant represented by the date. |
end |
datetime
|
First instant after the represented interval. |
Source code in rigour/dates.py
ended_before(value, reference)
Check whether a prefix date has completely elapsed.
Use this string wrapper for one-off end-date and age-cutoff checks. Parse once with prefix_interval when making several comparisons against the same value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
Canonical prefix date, from year through second precision. |
required |
reference
|
datetime
|
UTC point in time. Legacy naive values are interpreted as UTC; aware values are converted to UTC. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
reference. |
Source code in rigour/dates.py
interval_ended_before(value, reference)
Check whether an interval has completely elapsed before a point in time.
Use this for end dates and age cutoffs when the prefix date has already been parsed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
DateInterval
|
Interval to compare. |
required |
reference
|
datetime
|
Timezone-aware UTC point in time. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
reference. |
Source code in rigour/dates.py
interval_starts_after(value, reference)
Check whether an interval begins strictly after a point in time.
Use this for start dates and future-date guardrails when the prefix date has already been parsed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
DateInterval
|
Interval to compare. |
required |
reference
|
datetime
|
Timezone-aware UTC point in time. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in rigour/dates.py
parse_utc(value)
Parse an exact timestamp as an aware UTC datetime.
Use this at a prefix-date boundary where an exact timestamp may carry an offset. Naive timestamps use the ecosystem convention of implicit UTC.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
Canonical second-precision timestamp. |
required |
Returns:
| Type | Description |
|---|---|
datetime
|
The represented instant as a timezone-aware UTC datetime. |
Raises:
| Type | Description |
|---|---|
ValueError
|
The timestamp is invalid or is not precise to the second. |
Source code in rigour/dates.py
prefix_interval(value)
cached
Expand a canonical prefix date into its represented UTC interval.
Use this at the boundary between prefix-date strings and interval comparison. Feed it normalized property values only, not uncleaned source strings. Exact timestamps with offsets are converted to UTC before their one-second interval is constructed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
Canonical prefix date, from year through second precision. |
required |
Returns:
| Type | Description |
|---|---|
DateInterval
|
The timezone-aware UTC, half-open interval represented by the value. |
Raises:
| Type | Description |
|---|---|
ValueError
|
The value is invalid or non-canonical, or an imprecise value carries a timezone. |
Source code in rigour/dates.py
starts_after(value, reference)
Check whether a prefix date begins after a point in time.
Use this string wrapper for one-off start-date and future-date checks. Parse once with prefix_interval when reusing the same value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
Canonical prefix date, from year through second precision. |
required |
reference
|
datetime
|
UTC point in time. Legacy naive values are interpreted as UTC; aware values are converted to UTC. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
reference. |
Source code in rigour/dates.py
rigour.time
datetime_iso(dt)
Convert a datetime object or string to an ISO 8601 formatted string. If the input is None, it returns None. If the input is a string, it is returned as is. Otherwise, the datetime object is converted to a string in the format 'YYYY-MM-DDTHH:MM:SS' (with timezone suffix if present).
The function expects datetime objects to have UTC timezone. If a datetime with a different timezone is provided, a warning is emitted.
Source code in rigour/time.py
iso_datetime(value)
cached
Parse datetime from standardized date string. This expects an ISO 8601 formatted string, e.g. '2023-10-01T12:00:00'. Any additional characters after the seconds will be ignored. The string is converted to a datetime object with UTC timezone. This is not designed to parse all possible ISO 8601 formats, but rather a specific convention used in the context of the FollowTheMoney ecosystem.