Dates and times¶
This page collects practical recipes for std.datetime: reading clocks, parsing user input, formatting output, choosing the right interval type, and working with fixed UTC offsets.
Choose the right type¶
| Need | Type |
|---|---|
| Measure elapsed runtime work | Instant plus Duration |
| Store a system-clock timestamp | SystemTime |
| Store a calendar date | Date |
| Store a wall-clock time | Time |
| Store a date and time with no offset | DateTime |
| Store a date and time with a concrete UTC offset | DateTimeOffset |
| Add fixed days, seconds, or nanoseconds | TimeDelta |
| Add calendar years or months | YearMonthInterval |
| Add a compound civil interval | DateTimeInterval |
Read the clock¶
Use Instant.now() for monotonic measurement. Use SystemTime.now() for Unix timestamps. Use Date.utc_today() and DateTime.utc_now() when application code wants UTC civil values.
from std.datetime import Date, DateTime, DateTimeError, Duration, Instant, SystemTime
def record_clock() -> Result[None, DateTimeError]:
started = Instant.now()
deadline = started.checked_add(Duration.seconds(2))?
println(deadline.duration_since(started).whole_seconds())
println(SystemTime.now().unix_seconds())
println(Date.utc_today().isoformat())
println(DateTime.utc_now().isoformat())
return Ok(None)
Instant is monotonic and should not be serialized as a real-world timestamp. SystemTime is the host system clock and can move if the system clock is adjusted.
Parse ISO input¶
Use fromisoformat(...) for machine-readable input. It returns Result, so caller-visible parse failures stay explicit.
from std.datetime import Date, DateTime, DateTimeError, Time
def parse_inputs(date_text: str, time_text: str) -> Result[DateTime, DateTimeError]:
date = Date.fromisoformat(date_text)?
time = Time.fromisoformat(time_text)?
return Ok(DateTime.combine(date, time))
Useful ISO shapes:
| Type | Example |
|---|---|
Date |
"2026-04-14" |
Time |
"12:34:56" |
Time with nanoseconds |
"12:34:56.123456789" |
DateTime |
"2026-04-14T12:34:56" |
DateTimeOffset |
"2026-04-14T12:34:56+01:00" |
Parse custom text¶
Use strptime(value, format) when input is not ISO-shaped:
from std.datetime import Date, DateTime, DateTimeError
def parse_report_row(date_text: str, stamp_text: str) -> Result[DateTime, DateTimeError]:
report_date = Date.strptime(date_text, "%a %b %d %Y")?
parsed_stamp = DateTime.strptime(stamp_text, "%F %T.%f")?
println(report_date.isoformat())
return Ok(parsed_stamp)
The directive surface is Python-shaped. %f parses fractional seconds as nanoseconds, accepting up to nine digits and normalizing shorter fractions to nanosecond precision.
Format output¶
Prefer isoformat() for stable machine output. Use strftime(...) for display, legacy protocols, or logs.
from std.datetime import DateTime, DateTimeError
def render(stamp: DateTime) -> Result[None, DateTimeError]:
println(stamp.isoformat())
println(stamp.strftime("%Y-%m-%d %H:%M:%S.%f")?)
println(stamp.strftime("%a %b %_d %H:%M:%S %Y")?)
return Ok(None)
Use %F for %Y-%m-%d, %T for %H:%M:%S, and %f for nine-digit fractional seconds. The full directive table is in the std.datetime reference.
Add days, months, and compound intervals¶
Use the interval type that matches the domain:
from std.datetime import Date, DateTimeError, DateTimeInterval, TimeDelta, YearMonthInterval
def schedule(anchor_text: str) -> Result[None, DateTimeError]:
anchor = Date.fromisoformat(anchor_text)?
reminder = anchor + TimeDelta.days(7)
next_billing_cycle = anchor + YearMonthInterval.months(1)
compound = anchor + DateTimeInterval.new(months=1, days=3)
println(reminder.isoformat())
println(next_billing_cycle.isoformat())
println(compound.isoformat())
return Ok(None)
Do not replace YearMonthInterval.months(1) with a fixed number of days. Month arithmetic depends on the calendar.
Work with fixed offsets¶
Use DateTimeOffset for timestamps that carry a concrete offset:
from std.datetime import DateTime, DateTimeError, DateTimeOffset, FixedOffset
def render_offset_timestamp(value: str) -> Result[str, DateTimeError]:
local = DateTime.fromisoformat(value)?
stamp = DateTimeOffset(datetime=local, offset=FixedOffset.hours(1)?)
return stamp.strftime("%F %T.%f%:z")
%z formats offsets as +0100; %:z formats offsets as +01:00. Parsing accepts Z for UTC in ISO fixed-offset input, but named timezone directives are intentionally unsupported in std.datetime.
Handle parse and range failures¶
Temporal constructors return Result[..., DateTimeError] when input can be malformed or out of range:
from std.datetime import Date, DateTimeError
def print_date(value: str) -> None:
match Date.fromisoformat(value):
Ok(date) => println(date.isoformat())
Err(err) => println(err.message())
Use ? at boundaries that already return Result; use match when the caller can recover or provide a default.