A lightweight polyfill for Temporal, successor to the JavaScript Date object
Overall
score
96%
Evaluation — 96%
↑ 1.19xAgent success when using this tile
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.
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.
/**
* Represents a duration of time (time span)
*/
class Duration {
/** Creates a Duration from various inputs */
static from(item: DurationLike | string): Duration;
/** Compares two durations and returns -1, 0, or 1 */
static compare(one: DurationLike, two: DurationLike, options?: DurationArithmeticOptions): ComparisonResult;
/** Constructs a new Duration with specified components */
constructor(years?: number, months?: number, weeks?: number, days?: number, hours?: number, minutes?: number, seconds?: number, milliseconds?: number, microseconds?: number, nanoseconds?: number);
// Duration component properties
readonly years: number;
readonly months: number;
readonly weeks: number;
readonly days: number;
readonly hours: number;
readonly minutes: number;
readonly seconds: number;
readonly milliseconds: number;
readonly microseconds: number;
readonly nanoseconds: number;
// Computed properties
readonly sign: -1 | 0 | 1; // Sign of the duration
readonly blank: boolean; // True if duration is zero
// Duration manipulation methods
/** Returns a new Duration with the specified components changed */
with(durationLike: DurationLike): Duration;
/** Returns a new Duration with opposite sign */
negated(): Duration;
/** Returns a new Duration with absolute (positive) values */
abs(): Duration;
/** Returns a new Duration with the other duration added */
add(other: DurationLike, options?: DurationArithmeticOptions): Duration;
/** Returns a new Duration with the other duration subtracted */
subtract(other: DurationLike, options?: DurationArithmeticOptions): Duration;
// Precision and conversion methods
/** Rounds this duration to the specified unit or precision */
round(roundTo: DurationUnit | DurationRoundingOptions): Duration;
/** Returns the total duration in the specified unit as a number */
total(totalOf: DurationUnit | DurationTotalOfOptions): number;
// String representation methods
/** Returns a locale-formatted string representation */
toLocaleString(locales?: string | string[], options?: any): string;
/** Returns an ISO 8601 duration string representation */
toString(options?: DurationToStringOptions): string;
/** Returns a JSON representation (same as toString) */
toJSON(): string;
/** Throws a TypeError when used in comparison operators */
valueOf(): never;
}Usage Examples:
import { Temporal } from "temporal-polyfill";
// Creating durations
const twoHours = Temporal.Duration.from({ hours: 2 });
const fromString = Temporal.Duration.from('PT2H30M'); // 2 hours 30 minutes
const constructed = new Temporal.Duration(0, 0, 0, 0, 2, 30, 0); // 2 hours 30 minutes
const complex = Temporal.Duration.from({
years: 1,
months: 2,
days: 10,
hours: 8,
minutes: 30
});
// Duration arithmetic
const longer = twoHours.add({ minutes: 30 });
const shorter = twoHours.subtract({ minutes: 15 });
const combined = twoHours.add(Temporal.Duration.from('PT30M'));
// Duration properties
console.log(twoHours.hours); // 2
console.log(twoHours.minutes); // 0
console.log(twoHours.sign); // 1 (positive)
console.log(twoHours.blank); // false
// Negative durations
const backwards = twoHours.negated();
console.log(backwards.sign); // -1 (negative)
const positive = backwards.abs();
// Converting to totals
const totalMinutes = twoHours.total('minutes'); // 120
const totalSeconds = twoHours.total('seconds'); // 7200
const totalDays = complex.total({ unit: 'days', relativeTo: '2024-01-01' });
// Rounding durations
const precise = Temporal.Duration.from('PT2H23M47.123S');
const roundedToMinute = precise.round('minute');
const roundedUp = precise.round({ smallestUnit: 'minute', roundingMode: 'ceil' });
// Duration comparisons
const first = Temporal.Duration.from('PT2H');
const second = Temporal.Duration.from('PT90M'); // 1.5 hours
const comparison = Temporal.Duration.compare(first, second); // 1 (first > second)
// Using durations with dates
const startDate = Temporal.PlainDate.from('2024-01-01');
const futureDate = startDate.add(complex);
const duration = startDate.until(futureDate);Durations can be calendar-relative, meaning operations like adding months or years depend on the calendar system and starting date.
// Calendar-relative duration operations
interface DurationArithmeticOptions {
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
}
interface DurationTotalOfOptions {
unit: DurationUnit;
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
}Usage Examples:
import { Temporal } from "temporal-polyfill";
// Calendar-aware arithmetic
const oneMonth = Temporal.Duration.from({ months: 1 });
const jan31 = Temporal.PlainDate.from('2024-01-31');
// Adding 1 month to Jan 31 gives Feb 29 (2024 is leap year)
const feb29 = jan31.add(oneMonth);
// Duration calculations with relative anchor
const duration1 = Temporal.Duration.from({ months: 2, days: 10 });
const duration2 = Temporal.Duration.from({ days: 70 });
// Compare relative to a specific date
const comparison = Temporal.Duration.compare(
duration1,
duration2,
{ relativeTo: '2024-01-01' }
);
// Convert to total days relative to start date
const totalDays = duration1.total({
unit: 'days',
relativeTo: '2024-01-01'
}); // Takes into account actual month lengths
// Timezone-aware duration arithmetic
const zonedStart = Temporal.ZonedDateTime.from('2024-03-10T01:00:00[America/New_York]');
const dstDuration = Temporal.Duration.from({ hours: 3 });
// Handles DST transition - spring forward skips hour
const zonedEnd = zonedStart.add(dstDuration);
console.log(zonedStart.until(zonedEnd, { smallestUnit: 'hour' })); // PT3HDurations can be balanced and normalized to different unit combinations.
interface DurationRoundingOptions {
largestUnit?: DurationUnit;
smallestUnit: DurationUnit;
roundingIncrement?: number;
roundingMode?: RoundingMode;
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
}Usage Examples:
import { Temporal } from "temporal-polyfill";
// Duration balancing
const unbalanced = Temporal.Duration.from({
hours: 25,
minutes: 90,
seconds: 120
});
// Balance to show days and hours
const balanced = unbalanced.round({
largestUnit: 'day',
smallestUnit: 'minute'
});
console.log(balanced.toString()); // P1DT3H32M
// Fine-tune precision
const precise = Temporal.Duration.from('PT2H23M47.123456789S');
const toMillis = precise.round({
smallestUnit: 'millisecond',
roundingMode: 'halfExpand'
});
// Round to specific increments
const rounded15Min = precise.round({
smallestUnit: 'minute',
roundingIncrement: 15,
roundingMode: 'halfExpand'
});
// Balance relative to a date (for calendar units)
const mixed = Temporal.Duration.from({ days: 40, hours: 30 });
const balanced2 = mixed.round({
largestUnit: 'month',
smallestUnit: 'day',
relativeTo: '2024-01-01'
}); // Converts days to months based on actual month lengthsCommon patterns for using durations in business applications.
Usage Examples:
import { Temporal } from "temporal-polyfill";
// Meeting scheduling
function scheduleMeeting(
startTime: Temporal.ZonedDateTime,
duration: Temporal.Duration
): Temporal.ZonedDateTime {
return startTime.add(duration);
}
const meetingStart = Temporal.ZonedDateTime.from('2024-03-15T14:00:00[America/New_York]');
const meetingDuration = Temporal.Duration.from({ hours: 1, minutes: 30 });
const meetingEnd = scheduleMeeting(meetingStart, meetingDuration);
// Age calculation
function calculateAge(
birthDate: Temporal.PlainDate,
currentDate: Temporal.PlainDate = Temporal.Now.plainDateISO()
): Temporal.Duration {
return birthDate.until(currentDate, { largestUnit: 'year' });
}
const birthday = Temporal.PlainDate.from('1990-06-15');
const age = calculateAge(birthday);
console.log(`Age: ${age.years} years, ${age.months} months, ${age.days} days`);
// Time tracking
class TimeTracker {
private startTime: Temporal.Instant | null = null;
private totalDuration = Temporal.Duration.from({});
start(): void {
this.startTime = Temporal.Now.instant();
}
stop(): Temporal.Duration {
if (!this.startTime) {
throw new Error('Timer not started');
}
const elapsed = this.startTime.until(Temporal.Now.instant());
this.totalDuration = this.totalDuration.add(elapsed);
this.startTime = null;
return elapsed;
}
getTotal(): Temporal.Duration {
return this.totalDuration;
}
reset(): void {
this.totalDuration = Temporal.Duration.from({});
this.startTime = null;
}
}
// Service level agreement (SLA) calculations
function calculateSLAUptime(
downtimePeriods: Temporal.Duration[],
totalPeriod: Temporal.Duration
): number {
const totalDowntime = downtimePeriods.reduce(
(sum, period) => sum.add(period),
Temporal.Duration.from({})
);
const uptime = totalPeriod.subtract(totalDowntime);
return uptime.total('seconds') / totalPeriod.total('seconds');
}// Core type definitions for durations
type DurationLike = Duration | DurationFields | string;
interface DurationFields {
years?: number;
months?: number;
weeks?: number;
days?: number;
hours?: number;
minutes?: number;
seconds?: number;
milliseconds?: number;
microseconds?: number;
nanoseconds?: number;
}
// Unit types for duration operations
type DurationUnit = 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond' | 'microsecond' | 'nanosecond';
// Arithmetic and comparison options
interface DurationArithmeticOptions {
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
}
interface DurationRoundingOptions {
largestUnit?: DurationUnit;
smallestUnit: DurationUnit;
roundingIncrement?: number;
roundingMode?: RoundingMode;
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
}
interface DurationTotalOfOptions {
unit: DurationUnit;
relativeTo?: PlainDateLike | ZonedDateTimeLike | string;
}
// String representation options
interface DurationToStringOptions {
fractionalSecondDigits?: 'auto' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
smallestUnit?: DurationUnit;
roundingMode?: RoundingMode;
}
// Common rounding modes
type RoundingMode =
| 'ceil' // Round up (towards positive infinity)
| 'floor' // Round down (towards negative infinity)
| 'expand' // Round away from zero
| 'trunc' // Round towards zero
| 'halfCeil' // Round half up (towards positive infinity)
| 'halfFloor' // Round half down (towards negative infinity)
| 'halfExpand' // Round half away from zero (default)
| 'halfTrunc' // Round half towards zero
| 'halfEven'; // Round half to even (banker's rounding)
// Result type for comparisons
type ComparisonResult = -1 | 0 | 1;Install with Tessl CLI
npx tessl i tessl/npm-temporal-polyfilldocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10