date.min / max / resolution (and friends)

Fourteen class attributes, one idea: the edges of each type. min and max make good open-range sentinels; resolution is the smallest difference two values can have — one day for date, one microsecond for everything else.

class attributesPython 2.3+ (timezone 3.2+)Live demo
Common call
valid_until = date.max
Returns
datetime.date(9999, 12, 31)
Replaces
Magic sentinel dates like 9999-12-31 written by hand
Watch out
datetime.min/max are naive; timedelta.min is not -timedelta.max
date.min · date.max · date.resolution
→ date | datetime | time | timedelta | timezone

Demo

Live evaluation
Step inward from both ends of the date range — or past them.
Try:
Inputs
daysintdays to step
Code
from datetime import date, timedelta
(date.min + timedelta(days=1), date.max - timedelta(days=1))
Result
(datetime.date(1, 1, 2), datetime.date(9999, 12, 30))

date.min + 3652058 days is exactly date.max: the range holds 3,652,059 days. Stepping outside it by even one day is OverflowError: date value out of range. A million datetime.resolution steps make one second.

Attributes

AttributeTypeMeaning
date.min / date.maxdate0001-01-01 / 9999-12-31.
date.resolutiontimedeltatimedelta(days=1).
datetime.min / datetime.maxdatetime0001-01-01 00:00 / 9999-12-31 23:59:59.999999, both naive.
datetime.resolutiontimedeltatimedelta(microseconds=1).
time.min / time.maxtime00:00 / 23:59:59.999999, naive.
time.resolutiontimedeltatimedelta(microseconds=1).
timedelta.min / timedelta.maxtimedelta-999999999 days / 999999999 days, 23:59:59.999999.
timedelta.resolutiontimedeltatimedelta(microseconds=1).
timezone.min / timezone.maxtimezoneUTC-23:59 / UTC+23:59. There is no timezone.resolution.

Common patterns

Open-ended ranges
Use the extremes instead of None when the code compares a lot.
from datetime import date
start = row.start or date.min
end = row.end or date.max
active = start <= today <= end
Sort with missing values last
A key that maps None to the max sentinel.
from datetime import datetime
items.sort(key=lambda x: x.due or datetime.max)

Examples

1. date limits
from datetime import date (date.min, date.max, date.resolution)
Returns
(datetime.date(1, 1, 1), datetime.date(9999, 12, 31), datetime.timedelta(days=1))
2. datetime limits
from datetime import datetime (datetime.min, datetime.max)
Returns
(datetime.datetime(1, 1, 1, 0, 0), datetime.datetime(9999, 12, 31, 23, 59, 59, 999999))
3. time limits
from datetime import time (time.min, time.max, time.resolution)
Returns
(datetime.time(0, 0), datetime.time(23, 59, 59, 999999), datetime.timedelta(microseconds=1))
4. timedelta limits
from datetime import timedelta (timedelta.min, timedelta.max)
Returns
(datetime.timedelta(days=-999999999), datetime.timedelta(days=999999999, seconds=86399, microseconds=999999))
5. timezone limits
from datetime import timezone (str(timezone.min), str(timezone.max))
Returns
('UTC-23:59', 'UTC+23:59')
6. The whole datetime range
from datetime import datetime datetime.max - datetime.min
Returns
datetime.timedelta(days=3652058, seconds=86399, microseconds=999999)
7. No timezone.resolution
from datetime import timezone timezone.resolution
Returns
AttributeError: type object 'datetime.timezone' has no attribute 'resolution'

Pitfalls

1. Negating timedelta.max
The range is not symmetric: timedelta.max has 23:59:59.999999 on top of its days, so its negation needs one day more than timedelta.min allows.
-timedelta.max
from datetime import timedelta
-timedelta.max
OverflowError: days=-1000000000; must have magnitude <= 999999999
timedelta.min
from datetime import timedelta
timedelta.min
datetime.timedelta(days=-999999999)
2. Comparing datetime.max with aware values
datetime.min and datetime.max are naive. For aware comparisons attach a zone first.
naive sentinel
from datetime import datetime, UTC
datetime(2026, 9, 29, tzinfo=UTC) < datetime.max
TypeError: can't compare offset-naive and offset-aware datetimes
aware sentinel
from datetime import datetime, UTC
datetime(2026, 9, 29, tzinfo=UTC) < datetime.max.replace(tzinfo=UTC)
True

When to use

Use it
  • Sentinels for open date ranges and sort keys
  • Tests of edge handling (OverflowError paths)
Reach for something else
  • Sending max to systems with their own limits (databases, other languages) without checking their range

Notes

CPython impl
Class attributes created in Modules/_datetimemodule.c when the module is initialised
Naive
datetime.min, datetime.max, time.min and time.max have tzinfo=None
Resolution
date.resolution is one day; datetime, time and timedelta resolve to one microsecond
Asymmetry
timedelta.min == -timedelta(days=999999999) while timedelta.max is 999999999 days + 86399.999999 s

FAQ

datetime.max is 9999-12-31 23:59:59.999999 (naive). date.max is 9999-12-31 and time.max is 23:59:59.999999.