ZonedDateTime
This is a date with an epochTime and also a TimeZone. All ymd fields can be derived.
Create and Parse
Constructor
zdt = new Temporal.ZonedDateTime(
1709742442931429932n,
'America/Chicago',
'iso8601', // calendar system. optional
)From Fields
zdt = Temporal.ZonedDateTime.from({
// all are optional! (really?)
// fields
// day (day-of-month)
// timeZone
// calendar
})Can pass-in options.
From String
zdt = Temporal.ZonedDateTime.from(
'2024-03-06T11:29:06.340442931-05:00[America/New_York]'
)Can have [u-ca=hebrew] calendar at end of string.
Can pass-in options.
Now
Multiple methods:
Temporal.Now.zonedDateTimeISO()
Temporal.Now.zonedDateTime()
zdt = Temporal.Now.zonedDateTimeISO('America/Chicago')
// or
zdt = Temporal.Now.zonedDateTime({
timeZone: 'America/Chicago',
calendar: 'gregory'
})Get and Set
Common setter method.. new instance (immutable)..
.with()
You can combine multiple!
Here we go...
Year
Either use the simple year number or the era + eraYear (for supported calendars only).
.year
// get
zdt.year // 2024
// set
zdt2 = zdt.with({ year: 2025 }).era and .eraYear
zdt = Temporal.Now.zonedDateTime({
timeZone: 'America/Chicago',
calendar: 'gregory'
})
// get
zdt.era // 'bce'
zdt.eraYear // 2024
// set
zdt2 = zdt.with({
era: 'bc',
eraYear: 2,
}).inLeapYear
zdt.inLeapYear // falseCan't set.
Month
Is 1-based!
Either use the simple month number or the more portable monthCode.
.month
// get
zdt.month // 3
// set
zdt2 = zdt.with({ month: 4 }).monthCode
// get
zdt.monthCode // 'M03'
// set
zdt2 = zdt.with({ monthCode: 'M04' }).monthsInYear
Certain calendar systems might have different months in year:
zdt = Temporal.Now.zonedDateTime({
timeZone: 'America/Chicago',
calendar: 'hebrew'
})
// get
zdt.monthsInYear // 12Day of Month
Is 1-based!
The day-of-month, often simply called the date, is the day property in Temporal:
.day
// get
zdt.day // 6 (for March 6th)
// set
zdt.with({ day: 19 })Time
The wall-clock time has multiple properties:
.hour
// get
zdt.hour // 9
// set
zdt2 = zdt.with({ hour: 9 }).minute
// get
zdt.minute // 9
// set
zdt2 = zdt.with({ minute: 9 }).second
// get
zdt.second // 9
// set
zdt2 = zdt.with({ second: 9 }).millisecond
// get
zdt.millisecond // 9
// set
zdt2 = zdt.with({ millisecond: 9 }).microsecond
// get
zdt.microsecond // 9
// set
zdt2 = zdt.with({ microsecond: 9 }).nanosecond
// get
zdt.nanosecond // 9
// set
zdt2 = zdt.with({ nanosecond: 9 })Epoch Time
Time since epoch in various units
.epochSeconds
// get
zdt.epochSeconds // 123
// create-from
zdt2 = Temporal.Instant.fromEpochSeconds(23424)
.toZonedDateTime(zdt.getISOFields()) // timeZone/calendar.epochMilliseconds
// get
zdt.epochMilliseconds // 123
// create-from
zdt2 = Temporal.Instant.fromEpochMilliseconds(23424)
.toZonedDateTime(zdt.getISOFields()) // timeZone/calendar.epochMicroseconds
// get
zdt.epochMicroseconds // 123n - a bigint!
// create-from
zdt2 = Temporal.Instant.fromEpochMicroseconds(23424)
.toZonedDateTime(zdt.getISOFields()) // timeZone/calendar.epochNanoseconds
// get
zdt.epochNanoseconds // 123n - a bigint!
// create-from
zdt2 = new Temporal.ZonedDateTime(
23424n,
zdt.timeZone,
zdt.calendar,
)TimeZone Offset
Can be expressed:
.offsetNanoseconds
.offset
// get
zdt.offsetNanoseconds // a number
zdt.offset // a stringYou cannot set the offset. You must change the timezone...
TimeZone
Methods:
.timeZoneId
.getTimeZone()
.withTimeZone()
// get
timeZoneId = zdt.timeZoneId // 'America/Whatever'
timeZoneObj = zdt.getTimeZone() // Temporal.TimeZone {}
// set
zdt2 = zdt.withTimeZone('America/New_York')Read more about TimeZone objects.
Calendar
Methods:
.calendarId
.getCalendar()
.withCalendar()
// get
calendarId = zdt.calendarId // 'iso8601'
calendarObj = zdt.getCalendar() // Temporal.Calendar {}
// set
zdt2 = zdt.withCalendar('gregory')Read more about Calendar objects.
Week
Two concepts.
.weekOfYear
.yearOfWeek
Only works for supported calendars!
// get
zdt.weekOfYear // 89
zdt.yearOfWeek // 2024
// set weekOfYear
zdt1 = zdt.add({ weeks: 8 - zdt.weekOfYear })import { withWeekOfYear } from 'temporal-utils'
zdt1 = withWeekOfYear(zdt, 8)Day of Week
Explain 1 means Monday... This is REGARDLESS of locale. Always ISO
.dayOfWeek
// get
zdt.dayOfWeek // 4 (Thursday)
// set
zdt2 = zdt.add({ days: 6 - zdt.dayOfWeek })import { withDayOfWeek } from 'temporal-utils'
zdt2 = withDayOfWeek(zdt, 6)Day of Year
Is 1-based!!!
.dayOfYear
// get
zdt.dayOfYear // 89
// set
zdt2 = zdt.add({ days: 48 - zdt.dayOfYear })import { withDayOfYear } from 'temporal-utils'
zdt2 = withDayOfYear(zdt, 48)Days in Unit
Simple
.daysInYear
.daysInMonth
.daysInWeek
zdt.daysInYear // 366
zdt.daysInMonth // 23
zdt.daysInWeek // 7Hours in Day
Might be 23 or 25 if DST
zdt.hoursInDay // 24ISO Fields
// get
isoFields = zdt.getISOFields()
// {
// isoYear: 234,
// isoMonth: 234,
// isoDay: 234,
// isoHour: 234,
// isoMinute: 123,
// isoSecond: 123,
// isoMillisecond: 123,
// isoMicrosecond: 234,
// isoNanosecond: 123
// calendar: 'gregory',
// timeZone: 'America/Chicago',
// }
// create-from
zdt2 = new Temporal.PlainDateTime(
isoFields.isoYear,
isoFields.isoMonth,
isoFields.isoDay,
isoFields.isoHour,
isoFields.isoMinute,
isoFields.isoSecond,
isoFields.isoMillisecond,
isoFields.isoMicrosecond,
isoFields.isoNanosecond,
isoFields.calendar,
).toZonedDateTime(isoFields.timeZone)Math
Add and Subtract
Give a Duration or Duration-like fields:
.add()
zdt = Temporal.ZonedDateTime.from('2024-03-06T12:30[America/New_York]')
zdt2 = zdt.add({
year: 1,
months: 2,
})
// '2024-03-06T13:03:21.596195335-05:00[America/New_York]'.subtract()
zdt = Temporal.ZonedDateTime.from('2024-03-06T12:30[America/New_York]')
zdt2 = zdt.subtract({
year: 1,
months: 2,
})
// '2024-03-06T13:03:21.596195335-05:00[America/New_York]'There are options about overflow!
Round
For settings like roundingIncrement and roundingMode.
roundingMode:
- 'halfExpand' - like Math.round() - the default
- 'trunc' - like Math.trunc()
- 'floor' - like Math.floor()
- 'ceil' - like Math.ceil()
Only allows rounding to day/time! Not larger units like years/months/week!
Day:
zdt2 = zdt.round('day')
// or
zdt2 = zdt.round({
smallestUnit: 'day',
roundingMode: 'halfExpand' // or trunc/floor/ceil/etc
roundingIncrement: 1,
})Time:
zdt2 = zdt.round('hour') // or minute/second/millisecond/microsecond
// or
zdt2 = zdt.round({
smallestUnit: 'hour', // or minute/second/millisecond/microsecond
roundingMode: 'halfExpand' // or trunc/floor/ceil/etc
roundingIncrement: 1,
})Year:
import { roundToYear } from 'temporal-utils'
zdt2 = roundToYear(zdt)
// or
zdt2 = roundToYear(zdt, {
roundingMode: 'halfExpand' // or trunc/floor/ceil/etc
roundingIncrement: 1,
})Month:
import { roundToMonth } from 'temporal-utils'
zdt2 = roundToMonth(zdt)
// or
zdt2 = roundToMonth(zdt, {
roundingMode: 'halfExpand' // or trunc/floor/ceil/etc
roundingIncrement: 1,
})Week:
import { roundToWeek } from 'temporal-utils'
zdt2 = roundToWeek(zdt)
// or
zdt2 = roundToWeek(zdt, {
roundingMode: 'halfExpand' // or trunc/floor/ceil/etc
roundingIncrement: 1,
})Start of Unit
Start of year (might not be midnight):
zdt2 = zdt.with({ month: 1, day: 1 })
.startOfDay()import { startOfYear } from 'temporal-utils'
zdt2 = startOfYear(zdt)Start of month (might not be midnight):
zdt2 = zdt.with({ day: 1 })
.startOfDay()import { startOfMonth } from 'temporal-utils'
zdt2 = startOfMonth(zdt)Start of week:
zdt2 = zdt.add({ days: 1 - zdt.dayOfWeek })
.startOfDay()import { startOfWeek } from 'temporal-utils'
zdt2 = startOfWeek(zdt)Start of day (might not be midnight):
zdt2 = zdt.startOfDay()Start of hour:
zdt2 = zdt.round({
smallestUnit: 'hour',
roundingMode: 'floor',
})import { startOfHour } from 'temporal-utils'
zdt2 = startOfHour(zdt)Start of minute:
zdt2 = zdt.round({
smallestUnit: 'minute',
roundingMode: 'floor',
})import { startOfMinute } from 'temporal-utils'
zdt2 = startOfMinute(zdt)Start of second:
zdt2 = zdt.round({
smallestUnit: 'second',
roundingMode: 'floor',
})import { startOfSecond } from 'temporal-utils'
zdt2 = startOfSecond(zdt)Start of millisecond:
zdt2 = zdt.round({
smallestUnit: 'millisecond',
roundingMode: 'floor',
})import { startOfMillisecond } from 'temporal-utils'
zdt2 = startOfMillisecond(zdt)Start of microsecond:
zdt2 = zdt.round({
smallestUnit: 'microsecond',
roundingMode: 'floor',
})import { startOfMicrosecond } from 'temporal-utils'
zdt2 = startOfMicrosecond(zdt)End of Unit
Explain inclusive vs exclusive.
End of year (might not be midnight):
zdt2 = zdt.with({ month: 1, day: 1 })
.add({ years: 1 })
.startOfDay() // sufficient for exclusive end
.subtract({ nanoseconds: 1 }) // inclusive endimport { endOfYearExcl, endOfYearIncl } from 'temporal-utils'
zdt2 = endOfYearExcl(zdt)
zdt2 = endOfYearIncl(zdt)End of month (might not be midnight):
zdt2 = zdt.with({ day: 1 })
.add({ months: 1 })
.startOfDay() // sufficient for exclusive end
.subtract({ nanoseconds: 1 }) // inclusive endimport { endOfMonthExcl, endOfMonthIncl } from 'temporal-utils'
zdt2 = endOfMonthExcl(zdt)
zdt2 = endOfMonthIncl(zdt)End of day (might not be midnight):
zdt2 = zdt.add({ days: 1 })
.startOfDay() // sufficient for exclusive end
.subtract({ nanoseconds: 1 }) // inclusive endimport { endOfDayExcl, endOfDayIncl } from 'temporal-utils'
zdt2 = endOfDayExcl(zdt)
zdt2 = endOfDayIncl(zdt)End of hour:
zdt2 = zdt.round({ // sufficient for exclusive end
smallestUnit: 'hour',
roundingMode: 'ceil',
}).subtract({ nanoseconds: 1 }) // inclusive endimport { endOfHourExcl, endOfHourIncl } from 'temporal-utils'
zdt2 = endOfHourExcl(zdt)
zdt2 = endOfHourIncl(zdt)End of minute:
zdt2 = zdt.round({ // sufficient for exclusive end
smallestUnit: 'minute',
roundingMode: 'ceil',
}).subtract({ nanoseconds: 1 }) // inclusive endimport { endOfMinuteExcl, endOfMinuteIncl } from 'temporal-utils'
zdt2 = endOfMinuteExcl(zdt)
zdt2 = endOfMinuteIncl(zdt)End of second:
zdt2 = zdt.round({ // sufficient for exclusive end
smallestUnit: 'second',
roundingMode: 'ceil',
}).subtract({ nanoseconds: 1 }) // inclusive endimport { endOfSecondExcl, endOfSecondIncl } from 'temporal-utils'
zdt2 = endOfSecondExcl(zdt)
zdt2 = endOfSecondIncl(zdt)End of millisecond:
zdt2 = zdt.round({ // sufficient for exclusive end
smallestUnit: 'millisecond',
roundingMode: 'ceil',
}).subtract({ nanoseconds: 1 }) // inclusive endimport { endOfMillisecondExcl, endOfMillisecondIncl } from 'temporal-utils'
zdt2 = endOfMillisecondExcl(zdt)
zdt2 = endOfMillisecondIncl(zdt)End of microsecond:
zdt2 = zdt.round({ // sufficient for exclusive end
smallestUnit: 'microsecond',
roundingMode: 'ceil',
}).subtract({ nanoseconds: 1 }) // inclusive endimport { endOfMicrosecondExcl, endOfMicrosecondIncl } from 'temporal-utils'
zdt2 = endOfMicrosecondExcl(zdt)
zdt2 = endOfMicrosecondIncl(zdt)Difference
You can use .since instead! but best to be consistent with .until!
roundingMode:
- 'halfExpand' - like Math.round() - the default
- 'trunc' - like Math.trunc()
- 'floor' - like Math.floor()
- 'ceil' - like Math.ceil()
With all units. A Duration object.
zdt1 = Temporal.ZonedDateTime.from('2024-03-06T12:30[America/New_York]')
zdt2 = Temporal.ZonedDateTime.from('2024-03-06T12:30[America/New_York]')
dur = zdt1.until(zdt2, {
largestUnit: 'year',
smallestUnit: 'day',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
})
// Temporal.Duration {
// years: 1,
// months: 3,
// days: 2,
// hours: 0,
// minutes: 0,
// ...
// }With years:
yearsRounded = zdt1.until(zdt2, {
largestUnit: 'year',
smallestUnit: 'year',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
}).years // 6
yearsExact = zdt1.until(zdt2, {
largestUnit: 'year',
}).total({
unit: 'year',
relativeTo: zdt1,
}) // 6.5import { diffYears } from 'temporal-utils'
yearsRounded = diffYears(zdt1, zdt2, 'halfExpand')
yearsExact = diffYears(zdt1, zdt2)With months:
monthsRounded = zdt1.until(zdt2, {
largestUnit: 'month',
smallestUnit: 'month',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
}).months // 6
monthsExact = zdt1.until(zdt2, {
largestUnit: 'month',
}).total({
unit: 'month',
relativeTo: zdt1,
}) // 6.5import { diffMonths } from 'temporal-utils'
monthsRounded = diffMonths(zdt1, zdt2, 'halfExpand')
monthsExact = diffMonths(zdt1, zdt2)With weeks:
weeksRounded = zdt1.until(zdt2, {
largestUnit: 'week',
smallestUnit: 'week',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
}).weeks // 6
weeksExact = zdt1.until(zdt2, {
largestUnit: 'week',
}).total({
unit: 'week',
relativeTo: zdt1,
}) // 6.5import { diffWeeks } from 'temporal-utils'
weeksRounded = diffWeeks(zdt1, zdt2, 'halfExpand')
weeksExact = diffWeeks(zdt1, zdt2)With days:
daysRounded = zdt1.until(zdt2, {
largestUnit: 'day',
smallestUnit: 'day',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
}).days // 6
daysExact = zdt1.until(zdt2, {
largestUnit: 'day',
}).total({
unit: 'day',
relativeTo: zdt1,
}) // 6.5import { diffDays } from 'temporal-utils'
daysRounded = diffDays(zdt1, zdt2, 'halfExpand')
daysExact = diffDays(zdt1, zdt2)With hours:
hoursRounded = zdt1.until(zdt2, {
largestUnit: 'hour',
smallestUnit: 'hour',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
}).hours // 6
hoursExact = zdt1.until(zdt2, {
largestUnit: 'hour',
}).total('hour') // 6.5import { diffHours } from 'temporal-utils'
hoursRounded = diffHours(zdt1, zdt2, 'halfExpand')
hoursExact = diffHours(zdt1, zdt2)With minutes:
minutesRounded = zdt1.until(zdt2, {
largestUnit: 'hour',
smallestUnit: 'hour',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
}).hours // 6
minutesExact = zdt1.until(zdt2, {
largestUnit: 'hour',
}).total('hour') // 6.5import { diffMinutes } from 'temporal-utils'
minutesRounded = diffMinutes(zdt1, zdt2, 'halfExpand')
minutesExact = diffMinutes(zdt1, zdt2)With seconds:
secondsRounded = zdt1.until(zdt2, {
largestUnit: 'second',
smallestUnit: 'second',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
}).seconds // 6
secondsExact = zdt1.until(zdt2, {
largestUnit: 'second',
}).total('second') // 6.5import { diffSeconds } from 'temporal-utils'
secondsRounded = diffSeconds(zdt1, zdt2, 'halfExpand')
secondsExact = diffSeconds(zdt1, zdt2)With milliseconds:
msRounded = zdt1.until(zdt2, {
largestUnit: 'millisecond',
smallestUnit: 'millisecond',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
}).milliseconds // 6
msExact = zdt1.until(zdt2, {
largestUnit: 'millisecond',
}).total('millisecond') // 6.5import { diffMilliseconds } from 'temporal-utils'
msRounded = diffMilliseconds(zdt1, zdt2, 'halfExpand')
msExact = diffMilliseconds(zdt1, zdt2)With microseconds:
μsRounded = zdt1.until(zdt2, {
largestUnit: 'microsecond',
smallestUnit: 'microsecond',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
}).microseconds // 6
μsExact = zdt1.until(zdt2, {
largestUnit: 'microsecond',
}).total('microsecond') // 6.5import { diffMicroseconds } from 'temporal-utils'
μsRounded = diffMicroseconds(zdt1, zdt2, 'halfExpand')
μsExact = diffMicroseconds(zdt1, zdt2)With nanoseconds:
nsRounded = zdt1.until(zdt2, {
largestUnit: 'nanosecond',
smallestUnit: 'nanosecond',
roundingMode: 'halfExpand', // or trunc/floor/ceil/etc
roundingIncrement: 10,
}).nanoseconds
nsUnrounded = zdt2.epochNanoseconds - zdt1.epochNanosecondsimport { diffNanoseconds } from 'temporal-utils'
nsRounded = diffNanoseconds(zdt1, zdt2, 'halfExpand')
nsUnrounded = diffNanoseconds(zdt1, zdt2)Compare and Sort
zdt1 = Temporal.ZonedDateTime.from('2024-03-06T12:30[America/New_York]')
zdt2 = Temporal.ZonedDateTime.from('2024-03-06T12:30[America/New_York]')
Temporal.ZonedDateTime.compare(zdt1, zdt2)
// -1 because zdt1 < zdt2
Temporal.ZonedDateTime.compare(zdt1, zdt2)
// 1 because zdt1 > zdt2
Temporal.ZonedDateTime.compare(zdt1, zdt1)
// 0 because zdt1 = zdtPasthttps://tc39.es/proposal-temporal/docs/cookbook.html
Equality
epochNanoseconds, timeZone, and calendar must be identical.
zdt1 = Temporal.ZonedDateTime.from('2024-03-06T12:30[America/New_York]')
zdt2 = Temporal.ZonedDateTime.from('2024-03-06T12:30[America/New_York]')
zdt1.equals(zdt2) // false
zdt1.equals(zdt1) // true (of course it's equal to self)Stringify
ISO String
zdt.toString() // '2024-03-06T12:30[America/New_York]'For options, consult the spec.
Localized String
For options, consult Intl.DateTimeFormat options. The timeZone options is prohibited!
It's possible to call directly on the object:
// current locale
zdt.toLocaleString() // '3/6/2024, 3:58:45 PM EST'
// specific locale
zdt.toLocaleString('fr') // '06/03/2024 15:59:31 UTC−5'
// specific locale + options
zdt.toLocaleString('fr', { // 'mercredi 6 mars 2024'
dateStyle: 'full',
})However, it's much more performant to reuse a format:
dtf = new Intl.DateTimeFormat('fr', {
dateStyle: 'full'
})
dtf.format(zdt) // 'mercredi 6 mars 2024'Convert
Legacy Date
ZonedDateTime -> Date
legacyDate = new Date(zdt.epochMilliseconds)Date -> ZonedDateTime
zdt = legacyDate.toTemporalInstant().toZonedDateTimeISO(
Temporal.Now.timeZoneId(), // system time zone
)
// or
zdt = legacyDate.toTemporalInstant().toZonedDateTimeISO(
'America/Chicago',
)
// or
zdt = legacyDate.toTemporalInstant().toZonedDateTime({
timeZone: 'America/Chicago',
calendar: 'gregory',
})Instant
ZonedDateTime -> Instant
inst = zdt.toInstant()Instant -> ZonedDateTime
tzId = Temporal.Now.timeZoneId() // system time zone
tzId = 'America/Chicago' // specific time zone
// ISO calendar
zdt = inst.toZonedDateTimeISO(tzId)
// specific calendar
zdt = inst.toZonedDateTime({
timeZone: tzId,
calendar: 'gregory',
})PlainDateTime
ZonedDateTime -> PlainDateTime
pdt = zdt.toPlainDateTime()PlainDateTime -> ZonedDateTime
tzId = Temporal.Now.timeZoneId() // system time zone
tzId = 'America/Chicago' // OR a specific time zone
zdt = pdt.toZonedDateTime(tzId)Second argument can give more control.
PlainDate
ZonedDateTime -> PlainDate
pd = zdt.toPlainDate()PlainDate -> ZonedDateTime
zdt = pd.toZonedDateTime({
timeZone: Temporal.Now.timeZoneId(), // system time zone
})
// or
zdt = pd.toZonedDateTime({
timeZone: 'America/Chicago',
plainTime: '04:00' // optional. defaults to 00:00
})The plainTime option is anything a PlainTime accepts.
PlainTime
ZonedDateTime -> PlainTime
pt = zdt.toPlainTime()PlainTime -> ZonedDateTime
zdt = pt.toZonedDateTime({
timeZone: Temporal.Now.timeZoneId(), // system time zone
plainDate: '2023-04-04',
})
// or
zdt = pt.toZonedDateTime({
timeZone: 'America/Chicago',
plainDate: '2023-04-04',
})The plainDate option is anthing PlainDate accepts.
PlainYearMonth
ZonedDateTime -> PlainYearMonth
pym = zdt.toPlainYearMonth()PlainYearMonth -> ZonedDateTime
zdt = pym.toPlainDate({ day: 12 }).toZonedDateTime({
timeZone: 'America/Chicago',
plainTime: '04:00' // optional. defaults to 00:00
})The plainTime option is anything a PlainTime accepts.
PlainMonthDay
ZonedDateTime -> PlainMonthDay
pmd = zdt.toPlainMonthDay()PlainMonthDay -> ZonedDateTime
zdt = pmd.toPlainDate({ year: 2019 }).toZonedDateTime({
timeZone: 'America/Chicago',
plainTime: '04:00' // optional. defaults to 00:00
})The plainTime option is anything a PlainTime accepts.