0
# Duration and Arithmetic
1
2
Duration class for representing time spans and performing date arithmetic operations. Durations can represent time periods from nanoseconds to years and are essential for all temporal calculations.
3
4
## Capabilities
5
6
### Duration
7
8
Represents a duration of time with support for all time units from nanoseconds to years. Handles both positive and negative durations with precise arithmetic operations.
9
10
```typescript { .api }
11
/**
12
* Represents a duration of time (time span)
13
*/
14
class Duration {
15
/** Creates a Duration from various inputs */
16
static from(item: DurationLike | string): Duration;
17
/** Compares two durations and returns -1, 0, or 1 */
18
static compare(one: DurationLike, two: DurationLike, options?: DurationArithmeticOptions): ComparisonResult;
19
/** Constructs a new Duration with specified components */
20
constructor(years?: number, months?: number, weeks?: number, days?: number, hours?: number, minutes?: number, seconds?: number, milliseconds?: number, microseconds?: number, nanoseconds?: number);
21
22
// Duration component properties
23
readonly years: number;
24
readonly months: number;
25
readonly weeks: number;
26
readonly days: number;
27
readonly hours: number;
28
readonly minutes: number;
29
readonly seconds: number;
30
readonly milliseconds: number;
31
readonly microseconds: number;
32
readonly nanoseconds: number;
33
34
// Computed properties
35
readonly sign: -1 | 0 | 1; // Sign of the duration
36
readonly blank: boolean; // True if duration is zero
37
38
// Duration manipulation methods
39
/** Returns a new Duration with the specified components changed */
40
with(durationLike: DurationLike): Duration;
41
/** Returns a new Duration with opposite sign */
42
negated(): Duration;
43
/** Returns a new Duration with absolute (positive) values */
44
abs(): Duration;
45
/** Returns a new Duration with the other duration added */
46
add(other: DurationLike, options?: DurationArithmeticOptions): Duration;
47
/** Returns a new Duration with the other duration subtracted */
48
subtract(other: DurationLike, options?: DurationArithmeticOptions): Duration;
49
50
// Precision and conversion methods
51
/** Rounds this duration to the specified unit or precision */
52
round(roundTo: DurationUnit | DurationRoundingOptions): Duration;
53
/** Returns the total duration in the specified unit as a number */
54
total(totalOf: DurationUnit | DurationTotalOfOptions): number;
55
56
// String representation methods
57
/** Returns a locale-formatted string representation */
58
toLocaleString(locales?: string | string[], options?: any): string;
59
/** Returns an ISO 8601 duration string representation */
60
toString(options?: DurationToStringOptions): string;
61
/** Returns a JSON representation (same as toString) */
62
toJSON(): string;
63
/** Throws a TypeError when used in comparison operators */
64
valueOf(): never;
65
}
66
```
67
68
**Usage Examples:**
69
70
```typescript
71
import { Temporal } from "temporal-polyfill";
72
73
// Creating durations
74
const twoHours = Temporal.Duration.from({ hours: 2 });
75
const fromString = Temporal.Duration.from('PT2H30M'); // 2 hours 30 minutes
76
const constructed = new Temporal.Duration(0, 0, 0, 0, 2, 30, 0); // 2 hours 30 minutes
77
const complex = Temporal.Duration.from({
78
years: 1,
79
months: 2,
80
days: 10,
81
hours: 8,
82
minutes: 30
83
});
84
85
// Duration arithmetic
86
const longer = twoHours.add({ minutes: 30 });
87
const shorter = twoHours.subtract({ minutes: 15 });
88
const combined = twoHours.add(Temporal.Duration.from('PT30M'));
89
90
// Duration properties
91
console.log(twoHours.hours); // 2
92
console.log(twoHours.minutes); // 0
93
console.log(twoHours.sign); // 1 (positive)
94
console.log(twoHours.blank); // false
95
96
// Negative durations
97
const backwards = twoHours.negated();
98
console.log(backwards.sign); // -1 (negative)
99
const positive = backwards.abs();
100
101
// Converting to totals
102
const totalMinutes = twoHours.total('minutes'); // 120
103
const totalSeconds = twoHours.total('seconds'); // 7200
104
const totalDays = complex.total({ unit: 'days', relativeTo: '2024-01-01' });
105
106
// Rounding durations
107
const precise = Temporal.Duration.from('PT2H23M47.123S');
108
const roundedToMinute = precise.round('minute');
109
const roundedUp = precise.round({ smallestUnit: 'minute', roundingMode: 'ceil' });
110
111
// Duration comparisons
112
const first = Temporal.Duration.from('PT2H');
113
const second = Temporal.Duration.from('PT90M'); // 1.5 hours
114
const comparison = Temporal.Duration.compare(first, second); // 1 (first > second)
115
116
// Using durations with dates
117
const startDate = Temporal.PlainDate.from('2024-01-01');
118
const futureDate = startDate.add(complex);
119
const duration = startDate.until(futureDate);
120
```
121
122
### Calendar-Relative Arithmetic
123
124
Durations can be calendar-relative, meaning operations like adding months or years depend on the calendar system and starting date.
125
126
```typescript { .api }
127
// Calendar-relative duration operations
128
interface DurationArithmeticOptions {
129
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
130
}
131
132
interface DurationTotalOfOptions {
133
unit: DurationUnit;
134
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
135
}
136
```
137
138
**Usage Examples:**
139
140
```typescript
141
import { Temporal } from "temporal-polyfill";
142
143
// Calendar-aware arithmetic
144
const oneMonth = Temporal.Duration.from({ months: 1 });
145
const jan31 = Temporal.PlainDate.from('2024-01-31');
146
147
// Adding 1 month to Jan 31 gives Feb 29 (2024 is leap year)
148
const feb29 = jan31.add(oneMonth);
149
150
// Duration calculations with relative anchor
151
const duration1 = Temporal.Duration.from({ months: 2, days: 10 });
152
const duration2 = Temporal.Duration.from({ days: 70 });
153
154
// Compare relative to a specific date
155
const comparison = Temporal.Duration.compare(
156
duration1,
157
duration2,
158
{ relativeTo: '2024-01-01' }
159
);
160
161
// Convert to total days relative to start date
162
const totalDays = duration1.total({
163
unit: 'days',
164
relativeTo: '2024-01-01'
165
}); // Takes into account actual month lengths
166
167
// Timezone-aware duration arithmetic
168
const zonedStart = Temporal.ZonedDateTime.from('2024-03-10T01:00:00[America/New_York]');
169
const dstDuration = Temporal.Duration.from({ hours: 3 });
170
171
// Handles DST transition - spring forward skips hour
172
const zonedEnd = zonedStart.add(dstDuration);
173
console.log(zonedStart.until(zonedEnd, { smallestUnit: 'hour' })); // PT3H
174
```
175
176
### Duration Balancing and Normalization
177
178
Durations can be balanced and normalized to different unit combinations.
179
180
```typescript { .api }
181
interface DurationRoundingOptions {
182
largestUnit?: DurationUnit;
183
smallestUnit: DurationUnit;
184
roundingIncrement?: number;
185
roundingMode?: RoundingMode;
186
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
187
}
188
```
189
190
**Usage Examples:**
191
192
```typescript
193
import { Temporal } from "temporal-polyfill";
194
195
// Duration balancing
196
const unbalanced = Temporal.Duration.from({
197
hours: 25,
198
minutes: 90,
199
seconds: 120
200
});
201
202
// Balance to show days and hours
203
const balanced = unbalanced.round({
204
largestUnit: 'day',
205
smallestUnit: 'minute'
206
});
207
console.log(balanced.toString()); // P1DT3H32M
208
209
// Fine-tune precision
210
const precise = Temporal.Duration.from('PT2H23M47.123456789S');
211
const toMillis = precise.round({
212
smallestUnit: 'millisecond',
213
roundingMode: 'halfExpand'
214
});
215
216
// Round to specific increments
217
const rounded15Min = precise.round({
218
smallestUnit: 'minute',
219
roundingIncrement: 15,
220
roundingMode: 'halfExpand'
221
});
222
223
// Balance relative to a date (for calendar units)
224
const mixed = Temporal.Duration.from({ days: 40, hours: 30 });
225
const balanced2 = mixed.round({
226
largestUnit: 'month',
227
smallestUnit: 'day',
228
relativeTo: '2024-01-01'
229
}); // Converts days to months based on actual month lengths
230
```
231
232
### Working with Business Logic
233
234
Common patterns for using durations in business applications.
235
236
**Usage Examples:**
237
238
```typescript
239
import { Temporal } from "temporal-polyfill";
240
241
// Meeting scheduling
242
function scheduleMeeting(
243
startTime: Temporal.ZonedDateTime,
244
duration: Temporal.Duration
245
): Temporal.ZonedDateTime {
246
return startTime.add(duration);
247
}
248
249
const meetingStart = Temporal.ZonedDateTime.from('2024-03-15T14:00:00[America/New_York]');
250
const meetingDuration = Temporal.Duration.from({ hours: 1, minutes: 30 });
251
const meetingEnd = scheduleMeeting(meetingStart, meetingDuration);
252
253
// Age calculation
254
function calculateAge(
255
birthDate: Temporal.PlainDate,
256
currentDate: Temporal.PlainDate = Temporal.Now.plainDateISO()
257
): Temporal.Duration {
258
return birthDate.until(currentDate, { largestUnit: 'year' });
259
}
260
261
const birthday = Temporal.PlainDate.from('1990-06-15');
262
const age = calculateAge(birthday);
263
console.log(`Age: ${age.years} years, ${age.months} months, ${age.days} days`);
264
265
// Time tracking
266
class TimeTracker {
267
private startTime: Temporal.Instant | null = null;
268
private totalDuration = Temporal.Duration.from({});
269
270
start(): void {
271
this.startTime = Temporal.Now.instant();
272
}
273
274
stop(): Temporal.Duration {
275
if (!this.startTime) {
276
throw new Error('Timer not started');
277
}
278
const elapsed = this.startTime.until(Temporal.Now.instant());
279
this.totalDuration = this.totalDuration.add(elapsed);
280
this.startTime = null;
281
return elapsed;
282
}
283
284
getTotal(): Temporal.Duration {
285
return this.totalDuration;
286
}
287
288
reset(): void {
289
this.totalDuration = Temporal.Duration.from({});
290
this.startTime = null;
291
}
292
}
293
294
// Service level agreement (SLA) calculations
295
function calculateSLAUptime(
296
downtimePeriods: Temporal.Duration[],
297
totalPeriod: Temporal.Duration
298
): number {
299
const totalDowntime = downtimePeriods.reduce(
300
(sum, period) => sum.add(period),
301
Temporal.Duration.from({})
302
);
303
304
const uptime = totalPeriod.subtract(totalDowntime);
305
return uptime.total('seconds') / totalPeriod.total('seconds');
306
}
307
```
308
309
## Types
310
311
```typescript { .api }
312
// Core type definitions for durations
313
type DurationLike = Duration | DurationFields | string;
314
315
interface DurationFields {
316
years?: number;
317
months?: number;
318
weeks?: number;
319
days?: number;
320
hours?: number;
321
minutes?: number;
322
seconds?: number;
323
milliseconds?: number;
324
microseconds?: number;
325
nanoseconds?: number;
326
}
327
328
// Unit types for duration operations
329
type DurationUnit = 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond' | 'microsecond' | 'nanosecond';
330
331
// Arithmetic and comparison options
332
interface DurationArithmeticOptions {
333
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
334
}
335
336
interface DurationRoundingOptions {
337
largestUnit?: DurationUnit;
338
smallestUnit: DurationUnit;
339
roundingIncrement?: number;
340
roundingMode?: RoundingMode;
341
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
342
}
343
344
interface DurationTotalOfOptions {
345
unit: DurationUnit;
346
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
347
}
348
349
// String representation options
350
interface DurationToStringOptions {
351
fractionalSecondDigits?: 'auto' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
352
smallestUnit?: DurationUnit;
353
roundingMode?: RoundingMode;
354
}
355
356
// Common rounding modes
357
type RoundingMode =
358
| 'ceil' // Round up (towards positive infinity)
359
| 'floor' // Round down (towards negative infinity)
360
| 'expand' // Round away from zero
361
| 'trunc' // Round towards zero
362
| 'halfCeil' // Round half up (towards positive infinity)
363
| 'halfFloor' // Round half down (towards negative infinity)
364
| 'halfExpand' // Round half away from zero (default)
365
| 'halfTrunc' // Round half towards zero
366
| 'halfEven'; // Round half to even (banker's rounding)
367
368
// Result type for comparisons
369
type ComparisonResult = -1 | 0 | 1;
370
```