How do I work with Date and Time?
← Getting Started · Ref: Q31
EK9 has built-in Date and Time types with literal syntax, calendar-safe arithmetic, and rich operators. No imports or third-party libraries needed.
DATE: Calendar Date Without Time
Literal syntax: 2024-01-15, 1971-02-01
Constructor forms: Date(2020, 10, 03) or Date(daysFromEpoch) or Date(stringValue)
Unset constructor: Date() creates an unset date (not today). Get today: Date().today() returns the current date.
Accessors: year(), month(), day(), dayOfMonth(), dayOfWeek(), dayOfYear()
Arithmetic with Duration:
nextWeek <- birthday + P7D anniversary <- wedding + P1Y1M4D
Subtract two Dates to get a Duration:
age <- today - birthday
This is calendar-safe: adding P1M to January 31st gives February 28th (or 29th in a leap year), not an invalid date.
TIME: Time of Day Without Date
Literal syntax: 09:30:00, 14:15, 12:00:01
Constructor forms: Time(12, 00) or Time(12, 00, 01)
Unset constructor: Time() creates an unset time. Time().now() returns the current time.
Convenience: Time().startOfDay() gives 00:00:00, Time().endOfDay() gives 23:59:59
Accessors: hour(), minute(), second()
Arithmetic with Duration:
later <- morning + PT3H
Time wraps at 24 hours: adding PT3H to 22:00 gives 01:00, not 25:00.
Subtract two Times to get a Duration:
workHours <- 14:15 - 09:30:00
COMPARISON AND TRI-STATE
Both types support ==, <>, <, >, <=, >=, <=>. Like all EK9 types, Date and Time can be unset (see Q29). An unset date is different from any specific date.
DateTime combines date, time, and timezone into a single type (see Q92). Duration (P1Y1M4D) and Millisecond (500ms) are built-in temporal span types (see Q32, Q41). All temporal types support locale-aware formatting via the Locale type (see Q44).
Use 'ek9 -h Date' and 'ek9 -h Time' to see the full API for each type.
See Q32 for duration. See Q92 for datetime operations. See Q536-Q556 for deep-dive date, time, timezone, and duration coverage.
Example
defines module qa.date.time defines program DateTimeDemo() stdout <- Stdout() // === DATE === // Date literals (ISO 8601) birthday <- 1971-02-01 wedding <- 2020-10-03 stdout.println(`Birthday: ${birthday}`) stdout.println(`Wedding: ${wedding}`) // Constructor form sameWedding <- Date(2020, 10, 03) stdout.println(`Same wedding: ${sameWedding == wedding}`) // Date() is unset, Date().today() gets current date unsetDate <- Date() stdout.println(`Unset date isSet: ${unsetDate?}`) currentDate <- Date().today() stdout.println(`Today: ${currentDate}`) // Date accessors stdout.println(`Year: ${birthday.year()}, Month: ${birthday.month()}, Day: ${birthday.day()}`) stdout.println(`Day of week: ${birthday.dayOfWeek()}, Day of year: ${birthday.dayOfYear()}`) // Date + Duration arithmetic nextWeek <- birthday + P7D lastWeek <- birthday - P7D stdout.println(`Week after: ${nextWeek}, Week before: ${lastWeek}`) // Compound duration: one year, one month, four days anniversary <- wedding + P1Y1M4D stdout.println(`Anniversary + P1Y1M4D: ${anniversary}`) // Date - Date gives Duration gap <- anniversary - wedding stdout.println(`Gap: ${gap}`) // Compound assignment mutableDate <- 2024-01-15 mutableDate += P2W stdout.println(`After += P2W: ${mutableDate}`) // === TIME === // Time literals morning <- 09:30:00 afternoon <- 14:15 stdout.println(`Morning: ${morning}, Afternoon: ${afternoon}`) // Constructor forms noon <- Time(12, 00) precise <- Time(12, 00, 01) stdout.println(`Noon: ${noon}, Precise: ${precise}`) // Time() is unset unsetTime <- Time() stdout.println(`Unset time isSet: ${unsetTime?}`) // startOfDay and endOfDay dayStart <- Time().startOfDay() dayEnd <- Time().endOfDay() stdout.println(`Day start: ${dayStart}, Day end: ${dayEnd}`) // Time accessors stdout.println(`Hour: ${morning.hour()}, Minute: ${morning.minute()}, Second: ${morning.second()}`) // Time + Duration arithmetic later <- morning + PT3H earlier <- morning - PT1H stdout.println(`+3h: ${later}, -1h: ${earlier}`) // Time - Time gives Duration workHours <- afternoon - morning stdout.println(`Work hours: ${workHours}`) // Comparisons (use variables from function calls to avoid tautological conditions) if birthday < currentDate stdout.println("Birthday is in the past") currentTime <- Time().now() if morning < currentTime stdout.println("Morning is before current time")
Common mistakes
E50060 — EK9 built-in types use short method names without 'get' prefix. Date has year(), month(), day() not getYear(), getMonth(), getDay(). Triggers E50060 — method not resolved. See ek9 -h Date for the full API.
Incorrect:
birthday.getYear()
Correct:
birthday.year()
Other ways to ask this
- What date and time types does EK9 have?
- How do I use date literals in EK9?
- How does date arithmetic work in EK9?
Coming from another language?
Java: java.util.Date (broken), java.time.LocalDate/LocalTime (Java 8), no literals, verbose factory methods. Python: datetime.date/datetime.time, no literals, limited arithmetic. Rust: no built-in, chrono crate required. Go: time.Time only, no separate Date/Time, bizarre reference date format. JavaScript: Date object notoriously broken (months 0-indexed, mutable), no Time type. EK9: Date and Time built-in with literal syntax, calendar-safe arithmetic, Duration interop, no imports needed.
Keywords: month, arithmetic, duration, day, start, second, beginner, first, year, literal, intro, today, date, calendar, accessor, hour, time, minute