temporal-utils
August 13, 2026 · View on GitHub
Small, application-level helpers for working with native Temporal objects
Most helpers preserve the input type. For example, passing a
Temporal.PlainDateTime to startOfMonth returns a Temporal.PlainDateTime,
while passing a Temporal.ZonedDateTime returns a Temporal.ZonedDateTime.
Installation
npm install temporal-utils
temporal-utils does not ship a Temporal implementation of its own — a global
Temporal must already exist at runtime. See Requirements.
Usage
Import the helpers you need from the package root and call them on native Temporal objects. Each helper accepts a range of Temporal types and gives you back the same type you passed in:
import { startOfMonth, diffDays } from 'temporal-utils'
// Pass a PlainDate, get a PlainDate back
startOfMonth(Temporal.PlainDate.from('2024-07-20')).toString()
// '2024-07-01'
// Pass a ZonedDateTime, get a ZonedDateTime back
startOfMonth(
Temporal.ZonedDateTime.from('2024-07-20T12:30[America/New_York]'),
).toString()
// '2024-07-01T00:00:00-04:00[America/New_York]'
diffDays(
Temporal.PlainDate.from('2024-07-01'),
Temporal.PlainDate.from('2024-07-20'),
)
// 19
Requirements
temporal-utils operates on native Temporal objects but does not include
a Temporal implementation of its own. A global Temporal must already exist at
runtime — note that every example below references Temporal.* directly to
build its inputs. Ensure one is present in one of two ways:
-
Native
Temporal— available in newer browsers and runtimes, but support is still rolling out and remains incomplete. -
A polyfill — recommended for now. We suggest
temporal-polyfill, which installs a globalTemporal:import 'temporal-polyfill/global'
Function Reference
Field Replacement
These helpers fill gaps where Temporal exposes calendar-derived fields such as
dayOfYear, dayOfWeek, and weekOfYear, but does not provide direct
with({ ... }) fields for replacing them.
All field replacement helpers:
- accept
Temporal.PlainDate,Temporal.PlainDateTime, orTemporal.ZonedDateTime - truncate numeric input toward zero before applying it
- accept Temporal field overflow options:
{ overflow: 'constrain' }or{ overflow: 'reject' } - default overflow behavior to
'constrain'
withDayOfYear
Signature:
function withDayOfYear<
T extends Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(
date: T,
dayOfYear: number,
options?: Temporal.OverflowOptions,
): T
Returns the same calendar year with dayOfYear replaced. The time, time zone,
and calendar are preserved.
import { withDayOfYear } from 'temporal-utils'
const date = Temporal.PlainDate.from('2024-02-27')
withDayOfYear(date, 5).toString()
// '2024-01-05'
withDayOfYear(date, 500).toString()
// '2024-12-31'
withDayOfYear(date, 500, { overflow: 'reject' })
// RangeError
withDayOfWeek
Signature:
function withDayOfWeek<
T extends Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(
date: T,
dayOfWeek: number,
options?: Temporal.OverflowOptions,
): T
Returns the same ISO week with dayOfWeek replaced. Temporal uses ISO weekday
numbers: Monday is 1 and Sunday is 7.
import { withDayOfWeek } from 'temporal-utils'
const date = Temporal.PlainDate.from('2024-02-27') // Tuesday
withDayOfWeek(date, 4).toString()
// '2024-02-29'
withDayOfWeek(date, 8).toString()
// '2024-03-03'
withWeekOfYear
Signature:
function withWeekOfYear<
T extends Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(
date: T,
weekOfYear: number,
options?: Temporal.OverflowOptions,
): T
Returns the same ISO week-year with weekOfYear replaced, preserving the
current day of week. This helper is ISO-only and throws a RangeError for
calendars where Temporal does not expose ISO week fields.
import { withWeekOfYear } from 'temporal-utils'
const date = Temporal.PlainDate.from('2024-02-27') // Tuesday, week 9
withWeekOfYear(date, 27).toString()
// '2024-07-02'
withWeekOfYear(date.withCalendar('hebrew'), 27)
// RangeError
Difference Helpers
Single-unit difference helpers return a number for date0.until(date1). The
helpers are directional: reversing the arguments reverses the sign.
If no options are supplied, the result is the exact total in the requested unit.
Pass a RoundingMode string or a RoundingMathOptions object to request Temporal
rounding behavior for that unit.
import { diffDays, diffMonths } from 'temporal-utils'
const start = Temporal.PlainDate.from('2024-02-20')
const end = Temporal.PlainDate.from('2024-04-10')
diffMonths(start, end)
// approximately 1.677...
diffMonths(start, end, 'floor')
// 1
diffDays(start, end, { roundingMode: 'ceil', roundingIncrement: 7 })
// 56
Date and calendar unit helpers use relativeTo internally so totals account
for calendar units. For Temporal.ZonedDateTime, totals also account for
time-zone transitions. Time-unit helpers produce elapsed-time totals.
diffYears
Signature:
function diffYears(
date0: Temporal.PlainYearMonth | Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.PlainYearMonth | Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in years. Supported input types are
Temporal.PlainYearMonth, Temporal.PlainDate, Temporal.PlainDateTime, and
Temporal.ZonedDateTime.
diffMonths
Signature:
function diffMonths(
date0: Temporal.PlainYearMonth | Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.PlainYearMonth | Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in months. Supported input types are
Temporal.PlainYearMonth, Temporal.PlainDate, Temporal.PlainDateTime, and
Temporal.ZonedDateTime.
diffWeeks
Signature:
function diffWeeks(
date0: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in weeks. Supported input types are Temporal.PlainDate,
Temporal.PlainDateTime, and Temporal.ZonedDateTime.
diffDays
Signature:
function diffDays(
date0: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in days. Supported input types are Temporal.PlainDate,
Temporal.PlainDateTime, and Temporal.ZonedDateTime.
diffHours
Signature:
function diffHours(
date0: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in hours. Supported input types are Temporal.Instant,
Temporal.PlainTime, Temporal.PlainDateTime, and Temporal.ZonedDateTime.
diffMinutes
Signature:
function diffMinutes(
date0: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in minutes. Supported input types are Temporal.Instant,
Temporal.PlainTime, Temporal.PlainDateTime, and Temporal.ZonedDateTime.
diffSeconds
Signature:
function diffSeconds(
date0: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in seconds. Supported input types are Temporal.Instant,
Temporal.PlainTime, Temporal.PlainDateTime, and Temporal.ZonedDateTime.
diffMilliseconds
Signature:
function diffMilliseconds(
date0: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in milliseconds. Supported input types are
Temporal.Instant, Temporal.PlainTime, Temporal.PlainDateTime, and
Temporal.ZonedDateTime.
diffMicroseconds
Signature:
function diffMicroseconds(
date0: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in microseconds. Supported input types are
Temporal.Instant, Temporal.PlainTime, Temporal.PlainDateTime, and
Temporal.ZonedDateTime.
diffNanoseconds
Signature:
function diffNanoseconds(
date0: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
date1: Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
options?: RoundingMode | RoundingMathOptions,
): number
Returns the difference in nanoseconds. Supported input types are
Temporal.Instant, Temporal.PlainTime, Temporal.PlainDateTime, and
Temporal.ZonedDateTime.
Rounding Helpers
Calendar rounding helpers return the closest start of the named unit. They are
useful because Temporal's native .round() APIs cover day and smaller units,
but not every larger calendar unit in a uniform way across date-like types.
If options or options.roundingMode is omitted, roundingMode defaults to
'halfExpand'. Pass a RoundingMode string as shorthand for
{ roundingMode }.
RoundingMathOptions must not include smallestUnit; the helper name supplies
the unit. For the year, month, and week helpers, roundingIncrement must be
omitted or 1.
⚠️ The day and smaller roundTo* helpers are exported as codemod targets, not
as recommended hand-written API. In application code, prefer native Temporal
.round() directly:
dateTime.round({ smallestUnit: 'day' })
time.round({ smallestUnit: 'minute', roundingMode: 'ceil' })
instant.round({ smallestUnit: 'second' })
import { roundToMonth, roundToWeek, roundToYear } from 'temporal-utils'
const dateTime = Temporal.PlainDateTime.from('2024-07-20T12:30:00')
roundToYear(dateTime).toString()
// '2025-01-01T00:00:00'
roundToMonth(dateTime, 'floor').toString()
// '2024-07-01T00:00:00'
roundToWeek(dateTime, { roundingMode: 'floor' }).toString()
// '2024-07-15T00:00:00'
roundToYear
Signature:
function roundToYear<
T extends
| Temporal.PlainYearMonth
| Temporal.PlainDate
| Temporal.PlainDateTime
| Temporal.ZonedDateTime,
>(date: T, options?: RoundingMode | RoundingMathOptions): T
Rounds to the nearest year boundary. Supported input types are
Temporal.PlainYearMonth, Temporal.PlainDate, Temporal.PlainDateTime, and
Temporal.ZonedDateTime.
roundToMonth
Signature:
function roundToMonth<
T extends Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T, options?: RoundingMode | RoundingMathOptions): T
Rounds to the nearest month boundary. Supported input types are
Temporal.PlainDate, Temporal.PlainDateTime, and Temporal.ZonedDateTime.
roundToWeek
Signature:
function roundToWeek<
T extends Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T, options?: RoundingMode | RoundingMathOptions): T
Rounds to the nearest ISO week boundary. Supported input types are
Temporal.PlainDate, Temporal.PlainDateTime, and Temporal.ZonedDateTime.
⚠️ roundToDay
Signature:
function roundToDay<T extends Temporal.PlainDateTime | Temporal.ZonedDateTime>(
date: T,
options?: RoundingMode | RoundingMathOptions,
): T
Codemod target for rounding to the nearest day. Prefer
dateTime.round({ smallestUnit: 'day' }) in hand-written code.
⚠️ roundToHour
Signature:
function roundToHour<
T extends Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T, options?: RoundingMode | RoundingMathOptions): T
Codemod target for rounding to the nearest hour. Prefer
value.round({ smallestUnit: 'hour' }) in hand-written code.
⚠️ roundToMinute
Signature:
function roundToMinute<
T extends Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T, options?: RoundingMode | RoundingMathOptions): T
Codemod target for rounding to the nearest minute. Prefer
value.round({ smallestUnit: 'minute' }) in hand-written code.
⚠️ roundToSecond
Signature:
function roundToSecond<
T extends Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T, options?: RoundingMode | RoundingMathOptions): T
Codemod target for rounding to the nearest second. Prefer
value.round({ smallestUnit: 'second' }) in hand-written code.
⚠️ roundToMillisecond
Signature:
function roundToMillisecond<
T extends Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T, options?: RoundingMode | RoundingMathOptions): T
Codemod target for rounding to the nearest millisecond. Prefer
value.round({ smallestUnit: 'millisecond' }) in hand-written code.
⚠️ roundToMicrosecond
Signature:
function roundToMicrosecond<
T extends Temporal.Instant | Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T, options?: RoundingMode | RoundingMathOptions): T
Codemod target for rounding to the nearest microsecond. Prefer
value.round({ smallestUnit: 'microsecond' }) in hand-written code.
Start Of Unit
Start helpers truncate smaller fields to the beginning of the named unit.
startOfWeek uses ISO weeks, so the week starts on Monday.
For Temporal.ZonedDateTime, these helpers use Temporal's own field
replacement behavior. If local midnight is skipped by a time-zone transition,
Temporal resolves to the first real instant after the skipped wall time.
import { startOfMonth, startOfWeek } from 'temporal-utils'
const zdt = Temporal.ZonedDateTime.from('2024-07-20T12:30:00[America/New_York]')
startOfMonth(zdt).toString()
// '2024-07-01T00:00:00-04:00[America/New_York]'
startOfWeek(zdt).toString()
// '2024-07-15T00:00:00-04:00[America/New_York]'
startOfYear
Signature:
function startOfYear<
T extends
| Temporal.PlainYearMonth
| Temporal.PlainDate
| Temporal.PlainDateTime
| Temporal.ZonedDateTime,
>(date: T): T
Returns the start of the current year. For Temporal.PlainYearMonth, this is
January of the same year.
startOfMonth
Signature:
function startOfMonth<
T extends Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T): T
Returns the start of the current month.
startOfWeek
Signature:
function startOfWeek<
T extends Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T): T
Returns the start of the current ISO week, which is Monday.
startOfDay
Signature:
function startOfDay<T extends Temporal.PlainDateTime | Temporal.ZonedDateTime>(
dateTime: T,
): T
Returns midnight at the start of the current day.
startOfHour
Signature:
function startOfHour<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(dateTime: T): T
Returns the start of the current hour.
startOfMinute
Signature:
function startOfMinute<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(dateTime: T): T
Returns the start of the current minute.
startOfSecond
Signature:
function startOfSecond<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(dateTime: T): T
Returns the start of the current second.
startOfMillisecond
Signature:
function startOfMillisecond<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(dateTime: T): T
Returns the start of the current millisecond.
startOfMicrosecond
Signature:
function startOfMicrosecond<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(dateTime: T): T
Returns the start of the current microsecond.
End Of Unit
End helpers return the last representable value before the next unit begins.
For date-time and zoned date-time values, this means one nanosecond before the
exclusive end. For date-only values, it means one day before the exclusive end.
For Temporal.PlainYearMonth, endOfYear returns December of the same year.
import { endOfDay, endOfMonth } from 'temporal-utils'
const dateTime = Temporal.PlainDateTime.from('2024-07-20T12:30:00')
endOfDay(dateTime).toString()
// '2024-07-20T23:59:59.999999999'
endOfMonth(dateTime).toString()
// '2024-07-31T23:59:59.999999999'
endOfYear
Signature:
function endOfYear<
T extends
| Temporal.PlainYearMonth
| Temporal.PlainDate
| Temporal.PlainDateTime
| Temporal.ZonedDateTime,
>(date: T): T
Returns the last representable value in the current year.
endOfMonth
Signature:
function endOfMonth<
T extends Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T): T
Returns the last representable value in the current month.
endOfWeek
Signature:
function endOfWeek<
T extends Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T): T
Returns the last representable value in the current ISO week.
endOfDay
Signature:
function endOfDay<T extends Temporal.PlainDateTime | Temporal.ZonedDateTime>(
date: T,
): T
Returns the last representable value in the current day.
endOfHour
Signature:
function endOfHour<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T): T
Returns the last representable value in the current hour.
endOfMinute
Signature:
function endOfMinute<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T): T
Returns the last representable value in the current minute.
endOfSecond
Signature:
function endOfSecond<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T): T
Returns the last representable value in the current second.
endOfMillisecond
Signature:
function endOfMillisecond<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T): T
Returns the last representable value in the current millisecond.
endOfMicrosecond
Signature:
function endOfMicrosecond<
T extends Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime,
>(date: T): T
Returns the last representable value in the current microsecond.
Shared Types
RoundingMode
Type:
import type { RoundingMode } from 'temporal-utils'
RoundingMode is shared by the rounding and difference helpers.
RoundingMathOptions
Type:
import type { RoundingMathOptions } from 'temporal-utils'
RoundingMathOptions contains the rounding fields used by single-unit math
helpers.
The unit is implied by the helper name. For example, roundToWeek(date, options) forces smallestUnit: 'week' internally, and diffMonths(date0, date1, options) forces month-based difference math internally.