Skip to content

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 }

Four constructors live on the DateTime namespace. Each returns a DateTime<FixedOffset> internally, so every value always carries its timezone.

let now = DateTime.now() // local system time with local offset
let 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.

DateTime.parse(string) accepts multiple formats and returns the first successful parse:

// ISO 8601 / RFC 3339
let a = DateTime.parse("2024-01-15T10:30:00+00:00")
// RFC 2822
let 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:

FormatExample
RFC 3339 / ISO 86012024-01-15T10:30:00+00:00
RFC 2822Mon, 15 Jan 2024 10:30:00 +0000
ISO with offset2024-01-15T10:30:00-05:00
Date + time2024-01-15 10:30:00
Date + time (compact)2024-01-15T10:30:00
Date + hours:minutes2024-01-15 10:30
Date only (YYYY-MM-DD)2024-01-15
Date with slashes2024/01/15
US format01/15/2024
European format15-01-2024

DateTime.from_epoch(milliseconds) constructs a UTC datetime from Unix epoch milliseconds:

let epoch_ms = 1705314600000
let 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.

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 - 1w

Every DateTime exposes its individual date and time components as methods. All return int.

MethodReturnsExample
year()int2024
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()) // 2024
print(dt.month()) // 6
print(dt.day()) // 15
print(dt.hour()) // 14
print(dt.minute()) // 30
print(dt.second()) // 45

These methods help with calendar-aware logic like skipping weekends or grouping by week.

MethodReturnsDescription
day_of_week()int (0-6)0 = Monday, 6 = Sunday
day_of_year()int (1-366)Ordinal day of the year
week_of_year()intISO week number
is_weekday()boolTrue for Monday through Friday
is_weekend()boolTrue 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()) // true
print(dt.is_weekday()) // false
print(dt.day_of_year()) // 6
print(dt.week_of_year()) // 1

Four formatting methods cover the common output scenarios.

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:

SpecifierMeaningExample
%YYear (4-digit)2024
%mMonth (01-12)06
%dDay (01-31)15
%HHour 24h (00-23)14
%MMinute (00-59)30
%SSecond (00-59)00
%AWeekday nameSaturday
%BMonth nameJune
%ZTimezone nameUTC
%zUTC offset+0000
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.

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.

let utc_time = DateTime.parse("2024-06-15T12:00:00+00:00")
// Convert to a named IANA timezone
let nyc = utc_time.to_timezone("America/New_York")
print(nyc.hour()) // 8 (UTC-4 during EDT)
// Convert to UTC
let back = nyc.to_utc()
print(back.hour()) // 12
// Convert to system local timezone
let 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.

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".

MethodReturnsDescription
to_utc()DateTimeConvert to UTC (+00:00)
to_timezone(tz)DateTimeConvert to an IANA timezone
to_local()DateTimeConvert to system local timezone
timezone()stringCurrent timezone description
offset()stringUTC offset (e.g. "+05:30")

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()) // 30

add_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()) // 29

All add_* methods return a new DateTime. The original is never mutated.

MethodArgumentDescription
add_days(n)intAdd/subtract days
add_hours(n)intAdd/subtract hours
add_minutes(n)intAdd/subtract minutes
add_seconds(n)intAdd/subtract seconds
add_months(n)intAdd/subtract months (day clamped)

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 - b
print(diff) // 5 days as a duration
// DateTime + Duration produces a DateTime
let future = a + 3d
print(future.day()) // 18
// DateTime - Duration produces a DateTime
let past = a - 1w
print(past.day()) // 8

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)) // true
print(evening.is_after(morning)) // true
print(morning.is_same_day(evening)) // true

is_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 days
let 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)
MethodReturnsDescription
is_before(other)boolTrue if this DateTime is earlier
is_after(other)boolTrue if this DateTime is later
is_same_day(other)boolSame year, month, and day

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")
}
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 January
let mut current = start
let 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()}")
let event_time = DateTime.parse("2024-06-15T14:30:45+00:00")
// Human-readable
print(event_time.format("%B %d, %Y at %H:%M"))
// "June 15, 2024 at 14:30"
// ISO for APIs
let api_ts = event_time.iso8601()
// "2024-06-15T14:30:45+00:00"
// Epoch for databases
let db_ts = event_time.unix_timestamp()
// 1718461845
// Multi-timezone report
let 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')}")
}

All 30 methods at a glance, grouped by category.

CategoryMethodArgumentsReturns
Componentyear()int
Componentmonth()int
Componentday()int
Componenthour()int
Componentminute()int
Componentsecond()int
Componentmillisecond()int
Componentmicrosecond()int
Day Infoday_of_week()int
Day Infoday_of_year()int
Day Infoweek_of_year()int
Day Infois_weekday()bool
Day Infois_weekend()bool
Formattingformat(fmt)stringstring
Formattingiso8601()string
Formattingrfc2822()string
Formattingunix_timestamp()int
Timezoneto_utc()DateTime
Timezoneto_timezone(tz)stringDateTime
Timezoneto_local()DateTime
Timezonetimezone()string
Timezoneoffset()string
Arithmeticadd_days(n)intDateTime
Arithmeticadd_hours(n)intDateTime
Arithmeticadd_minutes(n)intDateTime
Arithmeticadd_seconds(n)intDateTime
Arithmeticadd_months(n)intDateTime
Comparisonis_before(other)DateTimebool
Comparisonis_after(other)DateTimebool
Comparisonis_same_day(other)DateTimebool
  • Asyncfor await over time-based event streams
  • Content — formatting DateTime values in styled output