RFC 058: std.datetime — temporal values, intervals, and runtime timing¶
- Status: Planned
- Created: 2026-04-14
- Author(s): Danny Meijer (@dannymeijer)
- Related:
- RFC 022 (namespaced stdlib modules and compiler handoff)
- RFC 023 (compilable stdlib and Rust module binding)
- RFC 055 (
std.fspath-centric filesystem APIs)
- Issue: https://github.com/dannys-code-corner/incan/issues/292
- RFC PR: —
- Written against: v0.2
- Shipped in: —
Summary¶
This RFC proposes std.datetime as Incan's standard library home for temporal values. The module covers runtime timing (Duration, Instant, SystemTime), civil and analytics-facing temporal values (Date, Time, DateTime, DateTimeTZ), and first-class interval types (TimeDelta, YearMonthInterval, DateTimeInterval). The design intentionally combines a Rust-shaped runtime timing model with a more analytics- and Substrait-shaped civil time model so Incan has one coherent temporal vocabulary for scheduling, timestamps, temporal arithmetic, and data-facing date or time work without dropping into Rust or treating time as raw strings and integers.
Motivation¶
Time is a foundational hole in the current stdlib surface. Programs need to measure elapsed work, represent timestamps, parse and format calendar values, and perform date arithmetic in analytics pipelines. Today, that story is fragmented: elapsed-time measurement pushes users toward Rust interop, while calendar-style dates, datetimes, and intervals have no clear standard home at all.
This matters across a broad slice of Incan code:
- CLIs, services, and workflow systems need durations, deadlines, and retry intervals.
- Analytics and ETL work need dates, datetimes, and interval arithmetic that are honest about month- and year-based semantics.
- Filesystem and process APIs eventually need a shared temporal vocabulary for metadata, timeouts, and scheduling.
- Tests need stable construction, parsing, and comparison helpers.
std.datetime should therefore give Incan one coherent temporal vocabulary instead of a mix of strings, integers, and Rust escape hatches.
Goals¶
- Provide a standard runtime timing story with
Duration,Instant, andSystemTime. - Provide a standard civil and analytics-facing temporal story with
Date,Time,DateTime, andDateTimeTZ. - Provide first-class interval types for analytics and temporal arithmetic rather than flattening everything into one duration-shaped abstraction.
- Support arithmetic, comparison, parsing, and formatting for the committed temporal types.
- Keep the user-facing surface Incan-first even when the runtime maps onto Rust primitives underneath.
- Keep core timezone support stable by standardizing
UTCand fixed offsets in the stdlib while allowing richer named-zone support to live in separately versioned packages.
Non-Goals¶
- Defining cron-like recurrence rules or workflow scheduler DSLs in this RFC.
- Standardizing named IANA timezone-database support in the core standard library.
- Providing locale-sensitive formatting as the primary formatting model.
- Replacing domain-specific time libraries that may later exist for finance, calendars, or recurrence.
Guide-level explanation¶
Authors should be able to use std.datetime for both elapsed-time measurement and data-facing temporal work.
from std.datetime import Duration, Instant
start = Instant.now()
run_job()?
elapsed = start.elapsed()
if elapsed > Duration.seconds(5):
println("job was slow")
from std.datetime import DateTimeTZ, FixedOffset
created_at = DateTimeTZ.now(tz=FixedOffset.hours(1))?
parsed = DateTimeTZ.fromisoformat("2026-04-14T12:34:56+01:00")?
if parsed < created_at:
println(parsed.isoformat())
from std.datetime import Date, TimeDelta, YearMonthInterval
anchor = Date.strptime("2026-04-14", "%Y-%m-%d")?
next_week = anchor + TimeDelta.days(7)
quarter_end = anchor + YearMonthInterval.months(3)
The mental model should be simple:
- use
Duration,Instant, andSystemTimefor runtime timing and deadlines; - use
Date,Time,DateTime, andDateTimeTZfor civil and external timestamp work; - use interval types for analytics-facing temporal arithmetic.
Reference-level explanation¶
Module scope¶
std.datetime is the standard library home for Incan temporal values. The committed family includes:
DurationInstantSystemTimeDateTimeDateTimeDateTimeTZUTCFixedOffsetTimeDeltaYearMonthIntervalDateTimeInterval
There is no separate std.time module in this design. Runtime timing and calendar-facing time belong in one coherent namespace because users need them together.
Semantic families¶
The module distinguishes three semantic families:
- runtime timing values for elapsed measurement and machine-clock work:
Duration,Instant,SystemTime - civil and external-facing values for dates, times, and timestamps:
Date,Time,DateTime,DateTimeTZ - analytics-facing interval values for temporal arithmetic:
TimeDelta,YearMonthInterval,DateTimeInterval
That split is normative. The public contract must not blur fixed elapsed time, civil timestamps, and calendar-relative intervals into one mushy abstraction.
Timestamp model¶
The timestamp split is explicit:
DateTimeis a naive datetime with no timezone or offset attached.DateTimeTZis a timezone-aware datetime.
Core stdlib timezone support is intentionally narrow:
UTCis part of the core surface.FixedOffsetis part of the core surface.- Named IANA timezone support is not part of
std.datetime.
That richer timezone story is expected to live in separately versioned packages, for example:
from pub::timezones @ 0.1 import TimeZone
Interval model¶
The interval model is also explicit:
Durationis the runtime elapsed-time type.TimeDeltais the Python-friendly day/time-style interval.YearMonthIntervalis the month/year-style interval.DateTimeIntervalis the compound interval type for analytics-facing temporal arithmetic.
This split is intentional. Duration is not the main analytics interval abstraction. Month- and year-based arithmetic must not be smuggled through fake fixed-length durations.
Arithmetic boundary¶
The arithmetic boundary is normative:
Instantcomposes withDuration.SystemTimecomposes withDuration.Date,DateTime, andDateTimeTZcompose withTimeDelta,YearMonthInterval, andDateTimeInterval.Instantmust not compose withTimeDelta,YearMonthInterval, orDateTimeInterval.
That keeps runtime timing and analytics-facing interval arithmetic distinct.
Parsing and formatting¶
The parsing and formatting story is complete and Python-shaped:
- canonical ISO helpers such as
isoformat()andfromisoformat(...)belong in the contract; - general
strftime(...)andstrptime(...)-style formatting and parsing belong in the contract as well. - fractional-second parsing and formatting must support up to 9 digits of precision.
However, Incan should standardize the supported format directives itself. The surface should look like Python, but it must not inherit Python's host-libc variability as part of the public contract.
Constructor and factory surface¶
The constructor and factory surface should be broad but consistent:
Durationuses unit-based factories such asweeks(...),days(...),hours(...),minutes(...),seconds(...),milliseconds(...),microseconds(...), andnanoseconds(...).Instantexposesnow()andelapsed()and composes withDuration.SystemTimeexposesnow().Date,Time,DateTime, andDateTimeTZsupport direct structural construction plusfromisoformat(...)andstrptime(...).Dateexposestoday().DateTimeexposesnow().DateTimeTZexposesnow(tz=...).TimeDeltauses unit-based factories analogous toDuration, including nanosecond precision.YearMonthIntervaluses explicityears(...)andmonths(...)factories.DateTimeIntervaluses an explicit composite constructor with keyword-style fields such asyears,months,days,hours,minutes,seconds, and fractional-second parts.
Python's constructor and parse/format surface is the right DX reference here, but not its precision ceiling. The north-star precision for Time, DateTime, DateTimeTZ, Duration, and TimeDelta is nanoseconds rather than microseconds.
TimeDelta and interval naming¶
The Python-shaped TimeDelta name remains the canonical public spelling because it is familiar and clear to users coming from Python. However, the module may also expose DayTimeInterval as an alias because that name aligns better with analytics and Substrait-style vocabulary.
That dual naming is justified here because both mental models are important in Incan:
- Python-style application and data users will look for
TimeDelta; - analytics-minded users will recognize
DayTimeIntervalimmediately.
The public contract should not generalize this into alias proliferation across the entire module. It is a targeted bridge for one type whose semantics are stable and already clearly defined.
DateTimeInterval semantics¶
DateTimeInterval is a single public compound interval type with structured internal components. It is not a scalar duration.
Its semantics should be:
- one public value containing year/month, day/time, and fractional-second components;
- safe normalization within each compatible bucket;
- no collapsing across the calendar-relative versus fixed-time boundary.
Normalization should include examples such as:
1500 milliseconds -> 1 second 500 milliseconds1500 microseconds -> 1 millisecond 500 microseconds1500 nanoseconds -> 1 microsecond 500 nanoseconds90 seconds -> 1 minute 30 seconds25 hours -> 1 day 1 hour15 months -> 1 year 3 months
But the module must not normalize:
1 month -> 30 days1 year -> 365 days
Comparison and equality are also intentionally constrained:
DateTimeIntervalmust not define a total ordering with<,<=,>, or>=;- normalized structural equality is valid;
- equality is fieldwise after normalization, not "same effect on every possible anchor date."
So examples such as the following should hold:
DateTimeInterval(months=15) == DateTimeInterval(years=1, months=3)DateTimeInterval(days=1, hours=24) == DateTimeInterval(days=2)DateTimeInterval(months=1) != DateTimeInterval(days=30)
When a DateTimeInterval is applied to Date, DateTime, or DateTimeTZ, the order of application must be fixed and documented:
- year/month portion first
- day/time/fractional portion second
Core calendar surface¶
The core contract should include more than raw field access, but it should stop short of becoming a full calendaring framework.
Included in the module contract:
- field accessors such as year, month, day, hour, minute, second, and nanosecond;
- arithmetic and comparison where meaningful;
- parsing and formatting;
weekday();iso_week();day_of_year();quarter();- ISO calendar conversion helpers such as
fromisocalendar(...)-style construction where appropriate.
Explicitly outside the module contract:
- locale-sensitive naming as a core semantic feature;
- non-Gregorian calendar systems;
- holiday or business-calendar logic;
- humanized relative-time phrases such as "3 days ago."
Design details¶
Why std.datetime instead of std.time¶
The module is broader than runtime timing. It covers dates, times, naive and aware datetimes, and multiple interval families in addition to Duration and Instant. Calling that whole surface std.time would undersell the civil and analytics half of the design. std.datetime is the more honest name.
Why runtime timing and calendar values live together¶
Real programs move between both worlds constantly: they read timestamps, compare them, add intervals, and also measure elapsed work or set deadlines. One module keeps the mental model coherent and prevents the temporal surface from fragmenting across multiple partially overlapping namespaces.
Python-shaped DX, Rust-shaped runtime, analytics-shaped intervals¶
This RFC deliberately blends three influences:
- Python for public parsing and formatting ergonomics and familiar names such as
TimeDelta; - Rust for runtime timing concepts such as
Duration,Instant, andSystemTime; - analytics and Substrait-style thinking for the interval taxonomy and the explicit split between naive and aware timestamp forms.
The goal is not to mirror any one of those ecosystems mechanically. The goal is to produce a better Incan temporal model than any single source provides by itself.
Why named IANA timezones stay out of core stdlib¶
Named timezone databases are useful, but they also bring churn, distribution concerns, and data-update cadence questions that should not destabilize the core standard library. The core contract therefore keeps timezone awareness stable and minimal with UTC and FixedOffset, while richer named-zone support belongs in separately versioned packages. That plays well with Incan's package model and avoids tying timezone-data updates to core language releases.
Interaction with existing and future features¶
std.fsmay eventually expose timestamps through metadata surfaces that should reusestd.datetimetypes.- Process or workflow RFCs will likely depend on
Durationfor timeouts and scheduling. - Analytics and data RFCs should use the interval taxonomy here rather than inventing their own competing time vocabulary.
- Rust interop remains the escape hatch for host-specific or high-precision temporal behavior not standardized here.
Compatibility / migration¶
This feature is additive. Existing code using raw integers or strings for time-like data keeps working, but new stdlib APIs should converge on this temporal vocabulary once std.datetime exists.
Alternatives considered¶
- Only runtime timing in stdlib
-
Too small. It leaves calendar, analytics, and timestamp work fragmented.
-
Only
datetime-style calendar values -
Too incomplete. It leaves elapsed-time measurement and timeout work without a standard story.
-
One generic
Intervaltype -
Too vague. It would blur fixed elapsed time, day/time intervals, and year/month intervals that behave differently in real analytics and scheduling work.
-
Named timezone support in core stdlib
-
Viable, but less stable. It couples the core temporal API to timezone-database churn and distribution policy.
-
Rust interop only
- Too implementation-shaped for ordinary Incan code and examples.
Drawbacks¶
- Time and interval semantics are notoriously easy to get subtly wrong.
- A broad temporal surface increases the design space substantially compared with narrower utility modules.
- Keeping named timezone support out of core stdlib means some users will need an extra package for richer awareness semantics.
Layers affected¶
- Stdlib / runtime: must provide the temporal types, interval types, and documented arithmetic and formatting semantics.
- Language surface: the module, types, constructors, operators, and methods must be available as specified.
- Execution handoff: implementations must preserve arithmetic, comparison, parsing, and formatting behavior without leaking backend quirks.
- Docs / examples: should standardize how Incan code measures elapsed time, works with timestamps, and performs interval arithmetic.
Design Decisions¶
- The module is
std.datetime; there is no separatestd.timenamespace. std.datetimeincludes runtime timing types, civil timestamp types, and analytics-facing interval types in one module.- The runtime timing family is
Duration,Instant, andSystemTime. - The civil timestamp family is
Date,Time,DateTime, andDateTimeTZ. DateTimeis naive;DateTimeTZis aware.- The interval family is
TimeDelta,YearMonthInterval, andDateTimeInterval. Durationis the runtime elapsed-time type, not the main analytics interval abstraction.Instantcomposes withDurationonly; analytics interval types do not apply toInstant.- Core timezone support is limited to
UTCandFixedOffset. - Named IANA timezone support is intentionally outside the core standard library and belongs in separately versioned packages.
- Parsing and formatting follow Python's overall
isoformat/fromisoformatandstrftime/strptimemodel, but the supported directives are standardized by Incan rather than inherited from host libc behavior. - The constructor and factory surface is broad and explicit: direct constructors for structural values,
now()/today()factories where appropriate,fromisoformat(...),strptime(...), and unit-based interval factories including nanoseconds. - Nanosecond precision is part of the north-star contract for
Duration,TimeDelta,Time,DateTime, andDateTimeTZ. TimeDeltaremains the canonical public name, withDayTimeIntervalallowed as an alias.DateTimeIntervalis a single compound public type with structured components, safe normalization within compatible buckets, structural equality after normalization, and no total ordering.- Applying a
DateTimeIntervalto civil temporal values uses a fixed order: year/month first, then day/time/fractional components. - The core calendar surface includes
weekday,iso_week,day_of_year,quarter, and ISO calendar conversion helpers, while excluding locale calendars, business calendars, and humanized relative-time strings.