CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-temporal-polyfill

A lightweight polyfill for Temporal, successor to the JavaScript Date object

Overall
score

96%

Evaluation96%

1.19x

Agent success when using this tile

Overview
Eval results
Files

instant-zoned-datetime.mddocs/

Instant and Zoned Date-Time

Classes for representing exact moments in time and timezone-aware date-times. These classes provide precise time handling with full timezone support and epoch-based calculations.

Capabilities

Instant

Represents a single moment in time measured from the Unix epoch. Ideal for timestamps, logging, and any application requiring precise time measurements.

/**
 * Represents a single moment in time (Unix timestamp)
 */
class Instant {
  /** Creates an Instant from various inputs */
  static from(item: InstantLike | string): Instant;
  /** Creates an Instant from epoch milliseconds */
  static fromEpochMilliseconds(epochMilliseconds: number): Instant;
  /** Creates an Instant from epoch nanoseconds */
  static fromEpochNanoseconds(epochNanoseconds: bigint): Instant;
  /** Compares two instants and returns -1, 0, or 1 */
  static compare(one: InstantLike, two: InstantLike): ComparisonResult;

  // Epoch time properties
  readonly epochMilliseconds: number;
  readonly epochNanoseconds: bigint;

  // Time manipulation methods
  /** Returns a new Instant with the duration added */
  add(duration: DurationLike): Instant;
  /** Returns a new Instant with the duration subtracted */
  subtract(duration: DurationLike): Instant;

  // Comparison and difference methods
  /** Returns the duration from this instant until the other instant */
  until(other: InstantLike, options?: DifferenceOptions<TimeUnit>): Duration;
  /** Returns the duration from the other instant since this instant */
  since(other: InstantLike, options?: DifferenceOptions<TimeUnit>): Duration;
  /** Rounds this instant to the specified unit or precision */
  round(roundTo: TimeUnit | RoundingOptions<TimeUnit>): Instant;
  /** Tests if this instant equals another instant */
  equals(other: InstantLike): boolean;

  // Conversion methods
  /** Converts this instant to a ZonedDateTime in the specified timezone */
  toZonedDateTimeISO(timeZone: TimeZoneLike): ZonedDateTime;

  // String representation methods
  /** Returns a locale-formatted string representation */
  toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
  /** Returns an ISO 8601 string representation */
  toString(options?: InstantToStringOptions): 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 instants
const now = Temporal.Now.instant();
const fromEpoch = Temporal.Instant.fromEpochMilliseconds(1640995200000);
const fromString = Temporal.Instant.from("2022-01-01T00:00:00Z");

// Converting from Date
const legacyDate = new Date();
const instant = legacyDate.toTemporalInstant();

// Time calculations
const oneHourLater = now.add({ hours: 1 });
const tenMinutesAgo = now.subtract({ minutes: 10 });

// Measuring time differences
const startTime = Temporal.Now.instant();
// ... do some work ...
const endTime = Temporal.Now.instant();
const elapsed = startTime.until(endTime, { smallestUnit: 'millisecond' });

// Rounding for precision
const roundedToSecond = now.round('second');
const roundedToMinute = now.round({ smallestUnit: 'minute', roundingMode: 'floor' });

// Timezone conversions
const inUtc = now.toZonedDateTimeISO('UTC');
const inNewYork = now.toZonedDateTimeISO('America/New_York');
const inTokyo = now.toZonedDateTimeISO('Asia/Tokyo');

// Comparisons
const isLater = Temporal.Instant.compare(oneHourLater, now) > 0;
const timeDiff = now.until(oneHourLater).total('minutes'); // 60

ZonedDateTime

Represents a date and time with timezone information. Combines all PlainDateTime functionality with timezone handling, DST awareness, and offset calculations.

/**
 * Represents a date and time with timezone information
 */
class ZonedDateTime {
  /** Creates a ZonedDateTime from various inputs */
  static from(item: ZonedDateTimeLike | string, options?: ZonedDateTimeAssignmentOptions): ZonedDateTime;
  /** Compares two zoned date-times and returns -1, 0, or 1 */
  static compare(one: ZonedDateTimeLike, two: ZonedDateTimeLike): ComparisonResult;

  // All PlainDateTime properties
  readonly calendarId: string;
  readonly year: number;
  readonly month: number;
  readonly monthCode: string;
  readonly day: number;
  readonly hour: number;
  readonly minute: number;
  readonly second: number;
  readonly millisecond: number;
  readonly microsecond: number;
  readonly nanosecond: number;
  readonly era: string | undefined;
  readonly eraYear: number | undefined;
  readonly dayOfWeek: number;
  readonly dayOfYear: number;
  readonly weekOfYear: number;
  readonly yearOfWeek: number;
  readonly daysInWeek: number;
  readonly daysInMonth: number;
  readonly daysInYear: number;
  readonly monthsInYear: number;
  readonly inLeapYear: boolean;

  // Timezone-specific properties
  readonly timeZoneId: string;
  readonly offset: string;
  readonly offsetNanoseconds: number;
  readonly epochMilliseconds: number;
  readonly epochNanoseconds: bigint;

  // Timezone-aware computed properties
  readonly hoursInDay: number;
  readonly startOfDay: ZonedDateTime;

  // DateTime manipulation methods (timezone-aware)
  /** Returns a new ZonedDateTime with the duration added */
  add(duration: DurationLike, options?: ArithmeticOptions): ZonedDateTime;
  /** Returns a new ZonedDateTime with the duration subtracted */
  subtract(duration: DurationLike, options?: ArithmeticOptions): ZonedDateTime;
  /** Returns a new ZonedDateTime with the specified fields changed */
  with(zonedDateTimeLike: ZonedDateTimeLike, options?: ZonedDateTimeAssignmentOptions): ZonedDateTime;
  /** Changes the calendar system of this zoned date-time */
  withCalendar(calendar: CalendarLike): ZonedDateTime;
  /** Changes the timezone of this zoned date-time */
  withTimeZone(timeZone: TimeZoneLike): ZonedDateTime;
  /** Changes the time portion of this zoned date-time */
  withPlainTime(plainTime?: PlainTimeLike): ZonedDateTime;

  // Comparison and difference methods
  /** Returns the duration from this zoned date-time until the other zoned date-time */
  until(other: ZonedDateTimeLike, options?: DifferenceOptions<DateTimeUnit>): Duration;
  /** Returns the duration from the other zoned date-time since this zoned date-time */
  since(other: ZonedDateTimeLike, options?: DifferenceOptions<DateTimeUnit>): Duration;
  /** Rounds this zoned date-time to the specified unit or precision */
  round(roundTo: DateTimeUnit | RoundingOptions<DateTimeUnit>): ZonedDateTime;
  /** Tests if this zoned date-time equals another zoned date-time */
  equals(other: ZonedDateTimeLike): boolean;

  // Conversion methods
  /** Converts this zoned date-time to an Instant */
  toInstant(): Instant;
  /** Converts this zoned date-time to a PlainDateTime (loses timezone) */
  toPlainDateTime(): PlainDateTime;
  /** Extracts the date portion */
  toPlainDate(): PlainDate;
  /** Extracts the time portion */
  toPlainTime(): PlainTime;
  /** Extracts the year-month portion */
  toPlainYearMonth(): PlainYearMonth;
  /** Extracts the month-day portion */
  toPlainMonthDay(): PlainMonthDay;
  /** Gets the TimeZone object for this zoned date-time */
  getTimeZone(): TimeZone;

  // String representation methods
  /** Returns a locale-formatted string representation */
  toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
  /** Returns an ISO 8601 string representation with timezone */
  toString(options?: ZonedDateTimeToStringOptions): 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 zoned date-times
const nowInNewYork = Temporal.Now.zonedDateTimeISO('America/New_York');
const fromString = Temporal.ZonedDateTime.from('2024-03-15T14:30:00-04:00[America/New_York]');
const fromObject = Temporal.ZonedDateTime.from({
  year: 2024,
  month: 3,
  day: 15,
  hour: 14,
  minute: 30,
  timeZone: 'America/New_York'
});

// From PlainDateTime
const plainDT = Temporal.PlainDateTime.from('2024-03-15T14:30:00');
const zonedDT = plainDT.toZonedDateTime('America/New_York');

// Timezone conversions
const inLondon = nowInNewYork.withTimeZone('Europe/London');
const inTokyo = nowInNewYork.withTimeZone('Asia/Tokyo');

// DST-aware arithmetic
const springForward = Temporal.ZonedDateTime.from('2024-03-10T01:30:00-05:00[America/New_York]');
const afterDST = springForward.add({ hours: 2 }); // Handles DST transition
console.log(springForward.hoursInDay); // 23 hours (spring forward day)

// Working with business hours
const businessDay = Temporal.ZonedDateTime.from('2024-03-15T09:00:00[America/New_York]');
const endOfDay = businessDay.with({ hour: 17, minute: 0 });
const workingHours = businessDay.until(endOfDay, { largestUnit: 'hour' });

// Handling ambiguous times (DST transitions)
const ambiguousTime = Temporal.ZonedDateTime.from(
  '2024-11-03T01:30:00[America/New_York]',
  { disambiguation: 'earlier' } // Choose first occurrence
);

// Time zone offset information
console.log(nowInNewYork.offset); // e.g., "-05:00" or "-04:00"
console.log(nowInNewYork.offsetNanoseconds); // Offset in nanoseconds

// Start of day in timezone (handles DST)
const startOfDay = nowInNewYork.startOfDay;
const midnight = nowInNewYork.with({ hour: 0, minute: 0, second: 0 });

// Conversions
const instant = nowInNewYork.toInstant();
const plainDateTime = nowInNewYork.toPlainDateTime();
const justDate = nowInNewYork.toPlainDate();

// Comparisons across timezones
const nyTime = Temporal.ZonedDateTime.from('2024-01-01T12:00:00[America/New_York]');
const londonTime = Temporal.ZonedDateTime.from('2024-01-01T17:00:00[Europe/London]');
const areEqual = nyTime.equals(londonTime); // true - same instant

Global Date Extension

Extension to the native Date object for converting to Temporal types.

/**
 * Extension to Date.prototype for Temporal integration
 */
interface Date {
  /** Converts a legacy Date to a Temporal.Instant */
  toTemporalInstant(): Instant;
}

Usage Examples:

// Converting legacy dates
const legacyDate = new Date();
const instant = legacyDate.toTemporalInstant();
const zonedDateTime = instant.toZonedDateTimeISO(Temporal.Now.timeZoneId());

// Migration pattern
function modernizeTimestamp(legacyTimestamp: Date): Temporal.ZonedDateTime {
  return legacyTimestamp
    .toTemporalInstant()
    .toZonedDateTimeISO('UTC');
}

Types

// Core type definitions for instants and zoned date-times
type InstantLike = Instant | string;
type ZonedDateTimeLike = ZonedDateTime | ZonedDateTimeFields | string;
type TimeZoneLike = string | TimeZone;

interface ZonedDateTimeFields {
  era?: string;
  eraYear?: number;
  year: number;
  month?: number;
  monthCode?: string;
  day: number;
  hour?: number;
  minute?: number;
  second?: number;
  millisecond?: number;
  microsecond?: number;
  nanosecond?: number;
  timeZone: TimeZoneLike;
  offset?: string;
  calendar?: CalendarLike;
}

// Timezone-specific options
type DisambiguationMode = 'compatible' | 'earlier' | 'later' | 'reject';
type OffsetDisambiguationMode = 'use' | 'ignore' | 'prefer' | 'reject';

interface ZonedDateTimeAssignmentOptions extends AssignmentOptions {
  disambiguation?: DisambiguationMode;
  offset?: OffsetDisambiguationMode;
}

// String formatting options
interface InstantToStringOptions {
  timeZone?: TimeZoneLike;
  fractionalSecondDigits?: 'auto' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
  smallestUnit?: TimeUnit;
  roundingMode?: RoundingMode;
}

interface ZonedDateTimeToStringOptions {
  fractionalSecondDigits?: 'auto' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
  smallestUnit?: DateTimeUnit;
  roundingMode?: RoundingMode;
  timeZoneName?: 'auto' | 'never' | 'critical';
  offset?: 'auto' | 'never';
  calendarName?: 'auto' | 'always' | 'never' | 'critical';
}

// TimeZone interface (for reference)
interface TimeZone {
  readonly id: string;
  getOffsetNanosecondsFor(instant: Instant): number;
  getOffsetStringFor(instant: Instant): string;
  getPlainDateTimeFor(instant: Instant, calendar?: CalendarLike): PlainDateTime;
  getInstantFor(dateTime: PlainDateTime, options?: ToInstantOptions): Instant;
  getPossibleInstantsFor(dateTime: PlainDateTime): Instant[];
  getNextTransition(startingPoint: Instant): Instant | null;
  getPreviousTransition(startingPoint: Instant): Instant | null;
  toString(): string;
  toJSON(): string;
}

interface ToInstantOptions {
  disambiguation?: DisambiguationMode;
}

Install with Tessl CLI

npx tessl i tessl/npm-temporal-polyfill

docs

calendar-system.md

current-time.md

date-time-classes.md

duration-arithmetic.md

index.md

instant-zoned-datetime.md

intl-formatting.md

tile.json