How do I work with Duration?
← Getting Started · Ref: Q32
Duration represents time spans using ISO 8601 literals. Starts with P, date components Y/M/W/D, T separates time H/M/S. M means months before T, minutes after T.
EXAMPLES
P1Y6M15D one year six months fifteen days, PT1H30M one hour thirty minutes, P3W three weeks (=P21D).
Arithmetic: +, -, */by Integer or Float, compound assignment. Accessors: .years(), .months(), .days(), .hours(), .minutes(), .seconds(). Comparison: ==, <>, <, >, <=, >=, <=>.
Use 'ek9 -h Duration' for the full API.
See Q31 for Date/Time. See Q41 for Millisecond. See Q44 for locale formatting. See Q539 for date differences.
Example
defines module qa.duration defines program DurationDemo() stdout <- Stdout() // === ISO 8601 DURATION FORMAT EXPLAINED === // The 'P' prefix means "Period" - every duration starts with P // After P, date components: Y=years, M=months, W=weeks, D=days // The 'T' separator introduces time components: H=hours, M=minutes, S=seconds // Note: M means months BEFORE the T, and minutes AFTER the T // Date-only durations (no T needed) oneYear <- P1Y twoMonths <- P2M tenDays <- P10D threeWeeks <- P3W stdout.println(`Year: ${oneYear}, Months: ${twoMonths}, Days: ${tenDays}, Weeks: ${threeWeeks}`) // Weeks convert to days: P3W equals P21D require threeWeeks == P21D // Time-only durations (PT prefix - P then T then time components) oneHour <- PT1H thirtyMinutes <- PT30M fortyFiveSeconds <- PT45S stdout.println(`Hour: ${oneHour}, Minutes: ${thirtyMinutes}, Seconds: ${fortyFiveSeconds}`) // Combined time: PT1H30M15S = 1 hour, 30 minutes, 15 seconds combinedTime <- PT1H30M15S stdout.println(`Combined time: ${combinedTime}`) // Combined date: P1Y6M15D = 1 year, 6 months, 15 days combinedDate <- P1Y6M15D stdout.println(`Combined date: ${combinedDate}`) // Full combined: P2Y3M10DT4H30M = 2 years, 3 months, 10 days, 4 hours, 30 minutes // The T separates date parts from time parts fullCombined <- P2Y3M10DT4H30M stdout.println(`Full: ${fullCombined}`) // Complex with weeks: P2Y6W3DT8H5M8S // = 2 years, 6 weeks, 3 days (=45 days), 8 hours, 5 minutes, 8 seconds withWeeks <- P2Y6W3DT8H5M8S stdout.println(`With weeks: ${withWeeks}`) // === COMPONENT ACCESSORS === d1 <- P2Y3M15DT4H30M45S stdout.println(`Years: ${d1.years()}, Months: ${d1.months()}, Days: ${d1.days()}`) stdout.println(`Hours: ${d1.hours()}, Minutes: ${d1.minutes()}, Seconds: ${d1.seconds()}`) // === DURATION ARITHMETIC === // Addition and subtraction morning <- PT2H30M afternoon <- PT4H15M totalWork <- morning + afternoon difference <- afternoon - morning stdout.println(`Total: ${totalWork}, Difference: ${difference}`) // Multiply by Integer or Float doubled <- PT1H * 2 tripled <- PT1H * 3 scaled <- PT1H * 1.5 stdout.println(`Doubled: ${doubled}, Tripled: ${tripled}, Scaled: ${scaled}`) // Divide by Integer or Float halved <- PT2H / 2 thirded <- PT3H / 3 stdout.println(`Halved: ${halved}, Thirded: ${thirded}`) // Compound assignment operators accumulator <- PT1H accumulator += PT30M require accumulator == PT1H30M accumulator -= PT15M require accumulator == PT1H15M accumulator *= 2 require accumulator == PT2H30M accumulator /= 2 require accumulator == PT1H15M stdout.println(`After compound ops: ${accumulator}`) // Negation positive <- PT5H negative <- -positive stdout.println(`Positive: ${positive}, Negative: ${negative}`) // === NEGATIVE DURATIONS === // Subtracting a later time from an earlier time gives a negative duration negDur <- 06:15:12 - 12:04:09 stdout.println(`Negative: ${negDur}`) require negDur == PT-5H-48M-57S // === DURATION FROM STRING === // Construct from a string representation fromString <- Duration("P1Y6M") stdout.println(`From string: ${fromString}`) // Convert to string with $ operator asString <- $fullCombined stdout.println(`As string: ${asString}`) roundTrip <- Duration(asString) require roundTrip == fullCombined // === COMPARISON === short <- PT30M long <- PT2H require short < long require long > short require short <> long require PT1H == PT1H require PT30M <= PT1H require PT2H >= PT1H stdout.println(`30min < 2h: ${short < long}`) // === UNSET DURATION === unset <- Duration() require ~unset? stdout.println(`Unset duration isSet: ${unset?}`) // === USING DURATIONS WITH DATES AND TIMES === // Date arithmetic with complex durations startDate <- 2020-01-15 later <- startDate + P1Y6M10D stdout.println(`Date + P1Y6M10D: ${later}`) earlier <- startDate - P2M stdout.println(`Date - P2M: ${earlier}`) // Time arithmetic with wrapping startTime <- 22:00 wrapped <- startTime + PT3H stdout.println(`22:00 + PT3H wraps to: ${wrapped}`) // DateTime arithmetic meeting <- 2024-06-15T10:30:00Z meetingEnd <- meeting + PT1H30M stdout.println(`Meeting ends: ${meetingEnd}`) // Subtracting temporal values produces a Duration dateGap <- 2024-12-25 - 2024-01-01 stdout.println(`Days until Christmas: ${dateGap}`) timeGap <- 17:30 - 09:00 stdout.println(`Work day: ${timeGap}`) // === MILLISECOND CONVERSION === // Millisecond to Duration timeout <- 5400ms asDuration <- timeout.duration() stdout.println(`5400ms as duration: ${asDuration}`) // Duration to Millisecond fromDuration <- Millisecond(P2W) stdout.println(`P2W as millis: ${fromDuration}`)
Common mistakes
E50060 — EK9 Duration uses short method names: hours(), minutes(), seconds() not getHours(), getMinutes(), getSeconds(). Triggers E50060 — method not resolved. See ek9 -h Duration for the full API.
Incorrect:
d1.getHours()
Correct:
d1.hours()
Other ways to ask this
- What is the ISO 8601 duration format?
- How do Duration literals work in EK9?
- How do I represent time spans in EK9?
- What does PT1H30M mean?
Coming from another language?
Java: verbose Duration.ofHours()/Period split. Python: timedelta, no months/years. Go/Rust/JS: no duration literals. EK9: ISO 8601 PT1H30M literals, unified type years through seconds.
Keywords: start, period, months, weeks, first, days, format, 8601, years, timing, duration, interval, minutes, millisecond, iso, intro, timespan, hours, literal, beginner, seconds, arithmetic