The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Create a calendar date | day = date(2026, 8, 12) | View examples |
| Move by elapsed days | tomorrow = day + timedelta(days=1) | View examples |
| Combine date and time | meeting = datetime.combine(day, time(9, 30)) | View examples |
| Read the current UTC instant | now = datetime.now(UTC) | View examples |
| Construct an aware datetime | instant = datetime(2026, 8, 12, 15, tzinfo=UTC) | View examples |
| Convert the same instant | local = instant.astimezone(target_zone) | View examples |
| Parse ISO-formatted text | value = datetime.fromisoformat('2026-08-12T15:30:00+00:00') | View examples |
| Emit ISO-formatted text | text = value.isoformat(timespec='seconds') | View examples |
| Parse a declared format | value = datetime.strptime(text, '%Y-%m-%d %H:%M') | View examples |
| Format for display | label = value.strftime('%Y-%m-%d %H:%M') | View examples |
| Load an IANA time zone | zone = ZoneInfo('America/Sao_Paulo') | View examples |
| Decode a POSIX timestamp | instant = datetime.fromtimestamp(timestamp, tz=UTC) | View examples |
| Advance a local schedule | next_run = local_run + timedelta(days=1) | View examples |
| Measure elapsed time | elapsed = end.astimezone(UTC) - start.astimezone(UTC) | View examples |
| Read a duration in seconds | seconds = duration.total_seconds() | View examples |
| Disambiguate a repeated wall time | later = local.replace(fold=1) | View examples |
Date and time code becomes reliable when it distinguishes calendar values, wall-clock readings, durations, and unique instants. Use aware datetimes for instants, UTC at storage and protocol boundaries, and named IANA zones when civil rules matter. Parse declared formats, preserve the original zone when it carries business meaning, and test transitions explicitly instead of relying on the machine's clock or local-zone configuration.
Step by step
Detailed examples
Choose the smallest temporal type that expresses the domain
date represents a calendar day, time represents wall-clock fields, datetime combines both, and timedelta represents a duration. These objects are immutable. A naive datetime has no usable UTC offset and cannot by itself identify a global instant; that can be correct for concepts such as an all-day birthday or a not-yet-zoned appointment. datetime assumes every civil day has exactly 86,400 seconds and does not model leap seconds.
from datetime import date, datetime, time, timedelta
leap_day = date(2024, 2, 28) + timedelta(days=1)
meeting = datetime.combine(leap_day, time(9, 30))
print(leap_day.isoformat())
print(meeting)
print(meeting.weekday()) 2024-02-29
2024-02-29 09:30:00
3Represent instants with aware datetimes
An aware datetime has a tzinfo object that supplies a UTC offset. Prefer datetime.now(UTC) over utcnow(), which has been deprecated since Python 3.12 because it returns a naive value that many methods interpret as local time. The UTC singleton was added in Python 3.11; timezone.utc is the compatible spelling on older Python versions. astimezone converts the same instant, while replace(tzinfo=new_zone) merely attaches new zone metadata and normally must not be used as a conversion.
from datetime import UTC, datetime, timedelta, timezone
instant = datetime(2025, 1, 15, 15, 0, tzinfo=UTC)
brt = timezone(timedelta(hours=-3), 'BRT')
local = instant.astimezone(brt)
print(instant.isoformat())
print(local.isoformat())
print(local.tzname())
print(local.astimezone(UTC) == instant) 2025-01-15T15:00:00+00:00
2025-01-15T12:00:00-03:00
BRT
TrueParse machine formats and presentation formats separately
fromisoformat and isoformat are the direct choices for supported ISO 8601 forms and preserve an included numeric offset. strptime handles a declared input format and rejects mismatches; strftime creates display text. A parsed numeric offset is fixed-offset metadata, not a historical IANA zone identity. Avoid ambiguous inputs, locale-dependent directives, and unbounded acceptance of many guessed formats. The complete strftime directive set varies because Python delegates some behavior to the platform C library.
from datetime import datetime
instant = datetime.fromisoformat('2025-08-12T14:05:09+00:00')
appointment = datetime.strptime('12 Aug 2025 14:05', '%d %b %Y %H:%M')
print(instant.isoformat(timespec='seconds'))
print(instant.strftime('%Y-%m-%d %H:%M %z'))
print(appointment.strftime('%Y-%m-%dT%H:%M')) 2025-08-12T14:05:09+00:00
2025-08-12 14:05 +0000
2025-08-12T14:05Use IANA zones for political civil-time rules
ZoneInfo, added in Python 3.9, applies the IANA database's historical and current offset rules. It reads system zone data and falls back to the first-party tzdata package; declare tzdata as a dependency when deployment platforms may lack a database. A ZoneInfo key such as America/Sao_Paulo is program data, not a user-friendly label. Rule changes can alter results for future dates, so pin and update time-zone data deliberately where reproducibility matters.
from datetime import UTC, datetime
from zoneinfo import ZoneInfo
instant = datetime(2024, 7, 1, 16, 0, tzinfo=UTC)
sao_paulo = instant.astimezone(ZoneInfo('America/Sao_Paulo'))
tokyo = instant.astimezone(ZoneInfo('Asia/Tokyo'))
print(instant.isoformat())
print(sao_paulo.isoformat())
print(tokyo.isoformat()) 2024-07-01T16:00:00+00:00
2024-07-01T13:00:00-03:00
2024-07-02T01:00:00+09:00Separate recurring wall time from elapsed duration
Adding one day to an aware local datetime advances its calendar fields and retains its zone, which is often right for a daily local schedule. Across an offset transition, the resulting instants can be 23 or 25 hours apart. When measuring elapsed time, convert endpoints to UTC before subtraction. Subtraction between aware datetimes that share the same tzinfo object ignores changing offsets and follows wall-clock arithmetic, so write tests around every transition relevant to the application.
from datetime import UTC, datetime, timedelta
from zoneinfo import ZoneInfo
new_york = ZoneInfo('America/New_York')
start = datetime(2024, 3, 9, 12, 0, tzinfo=new_york)
next_run = start + timedelta(days=1)
elapsed = next_run.astimezone(UTC) - start.astimezone(UTC)
print(start.isoformat())
print(next_run.isoformat())
print(elapsed)
print(elapsed.total_seconds() / 3600) 2024-03-09T12:00:00-05:00
2024-03-10T12:00:00-04:00
23:00:00
23.0Resolve repeated and missing wall-clock readings at input boundaries
When clocks move backward, two instants can share one local reading. PEP 495's fold attribute chooses the earlier offset with fold=0 and the later offset with fold=1. When clocks move forward, some local readings do not exist; attaching ZoneInfo does not validate or reject such a reading. Define a product policy for ambiguous and missing input, preserve an offset or fold when necessary, and prefer conversion from a known instant when ingesting timestamps.
from datetime import UTC, datetime
from zoneinfo import ZoneInfo
los_angeles = ZoneInfo('America/Los_Angeles')
earlier = datetime(2020, 11, 1, 1, 30, tzinfo=los_angeles, fold=0)
later = earlier.replace(fold=1)
print(earlier.isoformat())
print(later.isoformat())
print(later.astimezone(UTC) - earlier.astimezone(UTC)) 2020-11-01T01:30:00-07:00
2020-11-01T01:30:00-08:00
1:00:00Local code tester
Explore aware date-time conversion
Convert a fixed UTC instant to an explicit fixed offset without consulting the current clock or machine-local zone.
Press Run to load Python locally.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- Python Software Foundationdatetime — Basic date and time typesdocs.python.org
- Python Software Foundationzoneinfo — IANA time zone supportdocs.python.org
- Python Software FoundationPEP 495 — Local Time Disambiguationpeps.python.org
- Python Software FoundationPEP 615 — Support for the IANA Time Zone Database in the Standard Librarypeps.python.org
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



