DateTime
Shape provides first-class DateTime support with full IANA timezone handling, 30+ methods via O(1) PHF dispatch, and arithmetic on dates and durations.
All snippets below assume:
from std::core::intrinsics use { DateTime }Construction
Section titled “Construction”Four constructors live on the DateTime namespace. Each returns a
DateTime<FixedOffset> internally, so every value always carries its timezone.
Current Time
Section titled “Current Time”let now = DateTime.now() // local system time with local offsetlet utc = DateTime.utc() // current UTC time (+00:00)DateTime.now() uses the system clock and timezone. DateTime.utc() returns
the same instant pinned to the UTC offset. Both produce values you can
immediately compare, format, or do arithmetic on.
Parsing Strings
Section titled “Parsing Strings”DateTime.parse(string) accepts multiple formats and returns the first
successful parse:
// ISO 8601 / RFC 3339let a = DateTime.parse("2024-01-15T10:30:00+00:00")
// RFC 2822let b = DateTime.parse("Mon, 15 Jan 2024 10:30:00 +0000")
// Date + time (no timezone assumes UTC)let c = DateTime.parse("2024-01-15 10:30:00")
// Date only (midnight UTC)let d = DateTime.parse("2024-01-15")The parser tries formats in order: RFC 3339, RFC 2822, then common date/time patterns. When no timezone is present in the string, the result defaults to UTC.
Full list of accepted formats:
| Format | Example |
|---|---|
| RFC 3339 / ISO 8601 | 2024-01-15T10:30:00+00:00 |
| RFC 2822 | Mon, 15 Jan 2024 10:30:00 +0000 |
| ISO with offset | 2024-01-15T10:30:00-05:00 |
| Date + time | 2024-01-15 10:30:00 |
| Date + time (compact) | 2024-01-15T10:30:00 |
| Date + hours:minutes | 2024-01-15 10:30 |
| Date only (YYYY-MM-DD) | 2024-01-15 |
| Date with slashes | 2024/01/15 |
| US format | 01/15/2024 |
| European format | 15-01-2024 |
From Epoch
Section titled “From Epoch”DateTime.from_epoch(milliseconds) constructs a UTC datetime from Unix epoch
milliseconds:
let epoch_ms = 1705314600000let dt = DateTime.from_epoch(epoch_ms)print(dt.iso8601()) // "2024-01-15T10:30:00+00:00"This is useful when working with APIs or databases that store timestamps as integer milliseconds.
DateTime Literals
Section titled “DateTime Literals”The @"..." syntax creates a datetime literal directly in your source code:
let date = @"2024-01-15"let between = between @"2024-01-01" and @"2024-12-31"DateTime literals support arithmetic with duration suffixes:
let future = @"2024-06-15" + 30d - 1wComponent Access
Section titled “Component Access”Every DateTime exposes its individual date and time components as methods. All
return int.
| Method | Returns | Example |
|---|---|---|
year() | int | 2024 |
month() | int (1-12) | 1 |
day() | int (1-31) | 15 |
hour() | int (0-23) | 10 |
minute() | int (0-59) | 30 |
second() | int (0-59) | 45 |
millisecond() | int (0-999) | 250 |
microsecond() | int (0-999999) | 250000 |
let dt = DateTime.parse("2024-06-15T14:30:45+00:00")
print(dt.year()) // 2024print(dt.month()) // 6print(dt.day()) // 15print(dt.hour()) // 14print(dt.minute()) // 30print(dt.second()) // 45Day Information
Section titled “Day Information”These methods help with calendar-aware logic like skipping weekends or grouping by week.
| Method | Returns | Description |
|---|---|---|
day_of_week() | int (0-6) | 0 = Monday, 6 = Sunday |
day_of_year() | int (1-366) | Ordinal day of the year |
week_of_year() | int | ISO week number |
is_weekday() | bool | True for Monday through Friday |
is_weekend() | bool | True for Saturday and Sunday |
let dt = DateTime.parse("2024-01-06T12:00:00+00:00") // Saturday
print(dt.day_of_week()) // 5 (Saturday)print(dt.is_weekend()) // trueprint(dt.is_weekday()) // falseprint(dt.day_of_year()) // 6print(dt.week_of_year()) // 1Formatting
Section titled “Formatting”Four formatting methods cover the common output scenarios.
Custom Format
Section titled “Custom Format”Use the method form dt.format(fmt) for DateTime formatting. Bare
format(...) is a separate intrinsic formatter.
let dt = DateTime.parse("2024-06-15T14:30:00+00:00")
print(dt.format("%Y/%m/%d %H:%M")) // "2024/06/15 14:30"print(dt.format("%B %d, %Y")) // "June 15, 2024"print(dt.format("%A")) // "Saturday"Common format specifiers:
| Specifier | Meaning | Example |
|---|---|---|
%Y | Year (4-digit) | 2024 |
%m | Month (01-12) | 06 |
%d | Day (01-31) | 15 |
%H | Hour 24h (00-23) | 14 |
%M | Minute (00-59) | 30 |
%S | Second (00-59) | 00 |
%A | Weekday name | Saturday |
%B | Month name | June |
%Z | Timezone name | UTC |
%z | UTC offset | +0000 |
Standard Formats
Section titled “Standard Formats”let dt = DateTime.parse("2024-01-15T10:30:00+00:00")
dt.iso8601() // "2024-01-15T10:30:00+00:00"dt.rfc2822() // "Mon, 15 Jan 2024 10:30:00 +0000"dt.unix_timestamp() // 1705314600 (seconds since epoch, as int)iso8601() and rfc2822() return strings. unix_timestamp() returns an int
representing seconds since the Unix epoch.
Timezone Operations
Section titled “Timezone Operations”Shape uses chrono-tz for full IANA timezone support. Every DateTime carries a
fixed UTC offset, and conversion methods produce a new DateTime at the target
offset.
Converting Between Timezones
Section titled “Converting Between Timezones”let utc_time = DateTime.parse("2024-06-15T12:00:00+00:00")
// Convert to a named IANA timezonelet nyc = utc_time.to_timezone("America/New_York")print(nyc.hour()) // 8 (UTC-4 during EDT)
// Convert to UTClet back = nyc.to_utc()print(back.hour()) // 12
// Convert to system local timezonelet local = utc_time.to_local()The to_timezone() method accepts any IANA timezone string. If the timezone
name is invalid, a runtime error is raised.
Inspecting Timezone Info
Section titled “Inspecting Timezone Info”let dt = DateTime.parse("2024-01-15T10:00:00+05:30")
print(dt.timezone()) // "UTC+5:30"print(dt.offset()) // "+05:30"timezone() returns a human-readable name. For UTC, it returns "UTC".
Otherwise it returns the offset formatted as "UTC+H" or "UTC+H:MM".
offset() returns the raw UTC offset as a string like "+05:30" or "-05:00".
Summary
Section titled “Summary”| Method | Returns | Description |
|---|---|---|
to_utc() | DateTime | Convert to UTC (+00:00) |
to_timezone(tz) | DateTime | Convert to an IANA timezone |
to_local() | DateTime | Convert to system local timezone |
timezone() | string | Current timezone description |
offset() | string | UTC offset (e.g. "+05:30") |
Arithmetic
Section titled “Arithmetic”Adding Time
Section titled “Adding Time”Five add_* methods shift a DateTime forward or backward. Negative values move
backward.
let dt = DateTime.parse("2024-01-30T12:00:00+00:00")
let tomorrow = dt.add_days(1)print(tomorrow.day()) // 31
let later = dt.add_hours(5)print(later.hour()) // 17
let shifted = dt.add_minutes(45)print(shifted.minute()) // 45
let bumped = dt.add_seconds(30)print(bumped.second()) // 30add_months handles month-length differences by clamping to the last valid day:
let jan31 = DateTime.parse("2024-01-31T00:00:00+00:00")let feb = jan31.add_months(1)print(feb.day()) // 29 (2024 is a leap year)
let march = feb.add_months(1)print(march.day()) // 29All add_* methods return a new DateTime. The original is never mutated.
| Method | Argument | Description |
|---|---|---|
add_days(n) | int | Add/subtract days |
add_hours(n) | int | Add/subtract hours |
add_minutes(n) | int | Add/subtract minutes |
add_seconds(n) | int | Add/subtract seconds |
add_months(n) | int | Add/subtract months (day clamped) |
Operator Arithmetic
Section titled “Operator Arithmetic”The - and + operators work with DateTime and Duration (TimeSpan) values
directly:
let a = DateTime.parse("2024-06-15T12:00:00+00:00")let b = DateTime.parse("2024-06-10T12:00:00+00:00")
// DateTime - DateTime produces a Duration (in milliseconds)let diff = a - bprint(diff) // 5 days as a duration
// DateTime + Duration produces a DateTimelet future = a + 3dprint(future.day()) // 18
// DateTime - Duration produces a DateTimelet past = a - 1wprint(past.day()) // 8Comparisons
Section titled “Comparisons”Three comparison methods check temporal ordering:
let morning = DateTime.parse("2024-03-15T08:00:00+00:00")let evening = DateTime.parse("2024-03-15T22:30:00+00:00")
print(morning.is_before(evening)) // trueprint(evening.is_after(morning)) // trueprint(morning.is_same_day(evening)) // trueis_same_day compares year, month, and day components directly. Two DateTimes
at the same instant but in different timezones may have different calendar days:
// 23:00 EST and 04:00 UTC the next day are the same instant,// but different calendar dayslet est = DateTime.parse("2024-03-15T23:00:00-05:00")let utc = est.to_utc()print(est.is_same_day(utc)) // false (Mar 15 vs Mar 16)| Method | Returns | Description |
|---|---|---|
is_before(other) | bool | True if this DateTime is earlier |
is_after(other) | bool | True if this DateTime is later |
is_same_day(other) | bool | Same year, month, and day |
Practical Examples
Section titled “Practical Examples”Working with Business Hours Across Timezones
Section titled “Working with Business Hours Across Timezones”let office_open_et = DateTime.parse("2024-06-15T09:00:00-04:00")let office_close_et = DateTime.parse("2024-06-15T17:00:00-04:00")
// What time does the New York office open in Tokyo?let tokyo_open = office_open_et.to_timezone("Asia/Tokyo")print(f"NY office opens at {tokyo_open.format('%H:%M')} Tokyo time")// "NY office opens at 22:00 Tokyo time"
// Is the office open right now?let now = DateTime.now().to_timezone("America/New_York")if now.is_after(office_open_et) and now.is_before(office_close_et) { print("Office is open")}Date Range Iteration
Section titled “Date Range Iteration”let start = DateTime.parse("2024-01-01T00:00:00+00:00")let end = DateTime.parse("2024-01-31T00:00:00+00:00")
// Collect all weekdays in Januarylet mut current = startlet mut weekdays = []while current.is_before(end) or current.is_same_day(end) { if current.is_weekday() { weekdays = weekdays + [current.format("%Y-%m-%d")] } current = current.add_days(1)}print(f"Weekdays in January: {weekdays.length()}")Formatting for Display
Section titled “Formatting for Display”let event_time = DateTime.parse("2024-06-15T14:30:45+00:00")
// Human-readableprint(event_time.format("%B %d, %Y at %H:%M"))// "June 15, 2024 at 14:30"
// ISO for APIslet api_ts = event_time.iso8601()// "2024-06-15T14:30:45+00:00"
// Epoch for databaseslet db_ts = event_time.unix_timestamp()// 1718461845
// Multi-timezone reportlet zones = ["America/New_York", "Europe/London", "Asia/Tokyo"]for tz in zones { let local = event_time.to_timezone(tz) print(f"{tz}: {local.format('%H:%M %Z')}")}Method Reference
Section titled “Method Reference”All 30 methods at a glance, grouped by category.
| Category | Method | Arguments | Returns |
|---|---|---|---|
| Component | year() | — | int |
| Component | month() | — | int |
| Component | day() | — | int |
| Component | hour() | — | int |
| Component | minute() | — | int |
| Component | second() | — | int |
| Component | millisecond() | — | int |
| Component | microsecond() | — | int |
| Day Info | day_of_week() | — | int |
| Day Info | day_of_year() | — | int |
| Day Info | week_of_year() | — | int |
| Day Info | is_weekday() | — | bool |
| Day Info | is_weekend() | — | bool |
| Formatting | format(fmt) | string | string |
| Formatting | iso8601() | — | string |
| Formatting | rfc2822() | — | string |
| Formatting | unix_timestamp() | — | int |
| Timezone | to_utc() | — | DateTime |
| Timezone | to_timezone(tz) | string | DateTime |
| Timezone | to_local() | — | DateTime |
| Timezone | timezone() | — | string |
| Timezone | offset() | — | string |
| Arithmetic | add_days(n) | int | DateTime |
| Arithmetic | add_hours(n) | int | DateTime |
| Arithmetic | add_minutes(n) | int | DateTime |
| Arithmetic | add_seconds(n) | int | DateTime |
| Arithmetic | add_months(n) | int | DateTime |
| Comparison | is_before(other) | DateTime | bool |
| Comparison | is_after(other) | DateTime | bool |
| Comparison | is_same_day(other) | DateTime | bool |