datetime.hour / minute / second / microsecond / tzinfo / fold

Six read-only attributes, identical on datetime and time. tzinfo is what makes a value aware; fold (0 or 1) picks between the two occurrences of a repeated wall time when clocks go back.

datetime / time attributesPython 2.3+ (fold 3.6+)Live demo
Common call
dt.hour, dt.minute
Returns
(14, 30)
Replaces
Slicing "HH:MM" strings
Watch out
No millisecond attribute: dt.microsecond // 1000
dt.hour · dt.minute · dt.second · dt.microsecond · dt.tzinfo · dt.fold
→ int | tzinfo | None

Demo

Live evaluation
Parse a timestamp and read every time-of-day attribute.
Try:
Inputs
whenstran ISO 8601 timestamp
Code
from datetime import datetime
dt = datetime.fromisoformat('2026-09-29T14:30:05.25')
(dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo, dt.fold)
Result
(14, 30, 5, 250000, None, 0)

A fractional ".25" is 250000 microseconds (the digits are padded on the right), i.e. 250 milliseconds. tzinfo holds the zone object itself — timezone(timedelta(days=-1, seconds=72000)) for -04:00 — while fold stays 0 for anything parsed from text.

Attributes

AttributeTypeMeaning
hourint0..23.
minuteint0..59.
secondint0..59 (no leap second 60).
microsecondint0..999999. Milliseconds are microsecond // 1000.
tzinfotzinfo | NoneThe object passed as tzinfo=, or None for naive values. It is the zone object, not an offset — call utcoffset() for the offset.
foldint0 or 1 (3.6+). 1 = the second occurrence of an ambiguous local time. Ignored by comparisons and by fixed-offset zones.

Common patterns

Minutes since midnight
A compact sortable key for times of day.
minutes = dt.hour * 60 + dt.minute
Truncate to the minute
replace() the smaller fields with zero.
minute_start = dt.replace(second=0, microsecond=0)
Aware or naive?
tzinfo alone is not quite enough; utcoffset() must also be non-None.
aware = dt.tzinfo is not None and dt.utcoffset() is not None

Examples

1. The clock fields
from datetime import datetime dt = datetime(2026, 9, 29, 14, 30, 5, 250) (dt.hour, dt.minute, dt.second, dt.microsecond)
Returns
(14, 30, 5, 250)
2. tzinfo of naive and aware
from datetime import datetime, UTC (datetime(2026, 9, 29).tzinfo, datetime(2026, 9, 29, tzinfo=UTC).tzinfo)
Returns
(None, datetime.timezone.utc)
3. Same on time objects
from datetime import time t = time(9, 5, 30) (t.hour, t.minute, t.second)
Returns
(9, 5, 30)
4. fold is kept but not compared
from datetime import datetime a = datetime(2026, 11, 1, 1, 30, fold=1) (a.fold, a == a.replace(fold=0))
Returns
(1, True)
5. Read-only
from datetime import datetime dt = datetime(2026, 9, 29, 14) dt.hour = 15
Returns
AttributeError: attribute 'hour' of 'datetime.datetime' objects is not writable
6. A date has no hour
from datetime import date date(2026, 9, 29).hour
Returns
AttributeError: 'datetime.date' object has no attribute 'hour'

Pitfalls

1. Using tzinfo as the offset
tzinfo is the zone object. The offset of this particular datetime comes from utcoffset().
dt.tzinfo
from datetime import datetime
datetime.fromisoformat('2026-09-29T08:00-04:00').tzinfo
datetime.timezone(datetime.timedelta(days=-1, seconds=72000))
dt.utcoffset()
from datetime import datetime
datetime.fromisoformat('2026-09-29T08:00-04:00').utcoffset().total_seconds() / 3600
-4.0
2. Looking for a millisecond attribute
Only microsecond exists. Divide by 1000 — or format with isoformat(timespec="milliseconds").
.millisecond
from datetime import datetime
datetime(2026, 9, 29, 14, 30, 5, 250000).millisecond
AttributeError: 'datetime.datetime' object has no attribute 'millisecond'. Did you mean: 'microsecond'?
microsecond // 1000
from datetime import datetime
datetime(2026, 9, 29, 14, 30, 5, 250000).microsecond // 1000
250

When to use

Use it
  • Bucketing by hour, business-hours checks, custom labels
  • tzinfo to find out whether and how a value is zoned
Reach for something else
  • Changing a field → replace()
  • Formatting → strftime / isoformat

Notes

CPython impl
Read-only getset descriptors; fold is stored separately from the packed time bytes and does not take part in comparisons or hashing
fold
Only a tzinfo with DST transitions (zoneinfo) gives fold meaning: 01:30 on a fall-back night happens twice, fold=0 is the first
Also on
hour/minute/second/microsecond/tzinfo/fold exist on both datetime and time; date has none of them

FAQ

dt.hour and dt.minute — int attributes without parentheses. For text use dt.strftime("%H:%M").