completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Temporal

Learn the modern date and time API that fixes Date by choosing the right Temporal type for instants, plain calendar values, time zones, durations, calendars, and Date migration.

By the end, you will be able to
  • 01
    Pick the right Temporal typeTell apart an exact moment, a plain date, a plain clock time, and a time in a named place.
  • 02
    Do date math safelyAdd, compare, and measure dates with values that never change, instead of changing a Date object.
  • 03
    Move from Date to TemporalTurn an old Date's milliseconds number into a Temporal.Instant, and know what to use instead of common Date code.

Temporal is a toolbox for time

INTERACTIVE

JavaScript's old Date object tries to do every time job alone. One Date is used for all of these:

  • an exact moment, like "when this error happened"
  • a calendar date, like a birthday
  • a clock time, like "the shop opens at 09:00"
  • text for people to read

That makes mistakes easy. A Date can be changed by mistake. Its months start at 0. It reads some date text in surprising ways. And clock changes for summer time can break its math. The Date & time lesson shows each of these problems.

Temporal is the newer way to work with dates and times in JavaScript. It gives each job its own type. A type here is a kind of value, built for one job.

Temporal is new, and browsers are adding it one by one. Today these browsers have it:

  • Chrome 144 and later, and Edge 144 and later
  • Firefox 139 and later
  • Safari only in its preview version, and Safari on iPhone and iPad not at all

When this page opens, it checks whether your browser has Temporal. If it does, the live cards run real Temporal code. If it doesn't, they show example output instead and say so. Our tests check that example output in Node.js, using its --harmony-temporal setting, which turns Temporal on.

Temporal in your browser
Check if the browser has TemporalPop out in the code editor (opens in a new tab)JavaScript
const hasTemporal = typeof globalThis.Temporal !== "undefined";if (hasTemporal) {  Temporal.Now.plainDateISO().toString();}
Resultchecking

Temporal in your browser: checking once the page loads

Sample: Not checked yet

Try it yourself

The check runs once the page has loaded in your browser, so the page doesn't guess what your browser can do.

Browsers are adding Temporal one by one. Our tests run in Node.js 22 with its --harmony-temporal setting, which turns Temporal on.
Real-life analogyDate is a pocket knife; Temporal is a toolbox

A pocket knife with many blades is handy, because one object does many jobs. But to build a cupboard, you want a real saw, a real hammer, and a real screwdriver. Each tool does one job well. Temporal gives you a separate tool for each time job.

In real life: A stopwatch reading
In JavaScript: Temporal.Instant: one exact moment
In real life: A birthday on a paper calendar
In JavaScript: Temporal.PlainDate: a date with no clock time and no place
In real life: A clock face for a daily alarm
In JavaScript: Temporal.PlainTime: a clock time with no date
In real life: A flight leaving Mumbai at 09:00 local time
In JavaScript: Temporal.ZonedDateTime: a date, a clock time, and a place
In real life: A timer set for 90 minutes
In JavaScript: Temporal.Duration: a length of time

Try it now. Put each real situation with the Temporal type it needs. Read the explanation after each card.

Which Temporal type?
  • A time in a server log: 2024-03-10T06:30:00Z
  • A birthday: May 12, with no year needed for the reminder
  • The shop opens every day at 09:00
  • A meeting in Bengaluru at 10:00 on June 3
  • A monthly bill for February 2024
  • A countdown that lasts 1 hour 30 minutes
Try it yourself
0 of 6 correct

Put each situation with the Temporal type that fits it best. Each card explains why.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Temporal.Now & Instant

Temporal.Now gives you the current time. It has a few methods:

  • Temporal.Now.instant() gives the exact moment right now.
  • Temporal.Now.plainDateISO() gives today's date.

The current time changes every second, so the examples in this lesson use fixed times instead. That way the output is always the same, and our tests can check it.

An Instant is one exact moment. It means the same moment everywhere on Earth. Use it for:

  • lines in a server log
  • times saved in a database
  • the moment some saved data runs out
Make an Instant and print it two waysPop out in the code editor (opens in a new tab)JavaScript
const instant = Temporal.Instant.from("2024-03-10T06:30:00Z");console.log(instant.toString());console.log(instant.epochMilliseconds);
What the code prints (from a browser with Temporal)

2024-03-10T06:30:00Z

1710052200000

Line 1 makes an Instant from date text. Line 2 prints it as text again. The Z at the end means UTC, the world's shared base time.

Line 3 prints epochMilliseconds. That is the number of milliseconds since the start of 1970 in UTC. It is the same kind of number that the old Date.now() gives. So an Instant is an easy way to move from old Date code to Temporal.

PlainDate, PlainTime & PlainDateTime

STEP THROUGH

Three types start with the word "Plain". "Plain" means the value has no time zone. A time zone is a place's clock rules, like "New York time".

  • PlainDate is a date, like a birthday.
  • PlainTime is a clock time, like an opening time.
  • PlainDateTime is a date and a clock time together, like "January 31 at 09:30", before anyone says where.
Left: an Instant, 2024-03-10T06:30:00Z, is one exact moment, the same everywhere on Earth. Right: a PlainDate, 2024-01-31, is a date on a calendar, with no clock time and no place.Instant2024-03-10T06:30:00Zone exact momentthe same everywhere on EarthPlainDate2024-01-31a date on a calendarno clock time, no place
An Instant names one exact moment. The Z at the end means UTC, so everyone agrees which moment it is. A PlainDate is only a date, like a square on a paper calendar. It has no clock time and no place.
Make a date, a time, and both togetherPop out in the code editor (opens in a new tab)JavaScript
const date = Temporal.PlainDate.from("2024-01-31");const time = Temporal.PlainTime.from("09:30:15");const dateTime = Temporal.PlainDateTime.from("2024-01-31T09:30");console.log(date.toString());console.log(date.month);console.log(time.toString());console.log(dateTime.toString());

Lines 1 to 3 make one value of each type. Lines 4 to 7 print them.

Months start at 1, like on a real calendar. Temporal.PlainDate.from("2024-01-31").month is 1 for January, not 0.

Temporal values are also immutable. That means they never change after they are made. Methods like add and with don't change the date you call them on. They make a new date and give it back.

A box called original holds 2024-01-31. An arrow labelled add months 1 leads to a new box called later, which holds 2024-02-29. The original box still holds 2024-01-31.2024-01-31originalunchangedadd({ months: 1 })makes a new date2024-02-29laternew value
add() never changes the date you call it on. It makes a new date and gives it back. So original still holds January 31, and the new date, February 29, goes into later.
Date math that keeps the original
Step 0 of 6Ready
Your turn: follow the blue line

Step through how Temporal does date math without changing the original date. Change the number of months, then guess the new result.

Running in
  1. script
Next: line 1
const later = original.add({ months: 1 });const firstDay = original.with({ day: 1 });console.log(later.toString());console.log(firstDay.toString());console.log(original.toString());console.log(Temporal.PlainDate.compare(original, later));console.log(original.equals(Temporal.PlainDate.from("2024-01-31")));
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Change line 2: how many months should add use?

Picking a choice starts the steps again from the beginning.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

January has 31 days, but February doesn't. So what should "January 31 plus one month" be? Temporal lets you choose with the overflow option:

  • "constrain" (the default) moves the date back to the last real day of the month.
  • "reject" stops with an error instead.
Two ways to handle a day that doesn't existPop out in the code editor (opens in a new tab)JavaScript
const date = Temporal.PlainDate.from("2024-01-31");console.log(date.add({ months: 1 }).toString());try {  console.log(date.add({ months: 1 }, { overflow: "reject" }).toString());} catch (error) {  console.log(error.name);}
What the overflow code prints

2024-02-29

RangeError

Line 2 uses the default, so it prints the last day of February 2024. Line 4 asks for reject, so add throws an error. Line 6 prints the error's name, RangeError. Use reject when a day that doesn't exist should count as a mistake in the user's input.

Change only the day with with()Pop out in the code editor (opens in a new tab)JavaScript
const date = Temporal.PlainDate.from("2024-05-12");const appointment = date.with({ day: 20 });console.log(appointment.toString());console.log(date.toString());
What the with() code prints

2024-05-20

2024-05-12

with makes a new date with only the part you name changed. Here it changes the day to 20. Line 4 prints the first date again, and it is still May 12.

Put dates in orderPop out in the code editor (opens in a new tab)JavaScript
const dates = ["2024-05-12", "2023-12-01", "2024-01-31"]  .map((value) => Temporal.PlainDate.from(value));dates.sort((left, right) => Temporal.PlainDate.compare(left, right));console.log(dates.map((date) => date.toString()).join(", "));
The dates in order

2023-12-01, 2024-01-31, 2024-05-12

Lines 1 and 2 turn three date texts into PlainDate values. Line 3 sorts them. Temporal.PlainDate.compare takes two dates. It gives -1 if the first is earlier, 0 if they are the same, and 1 if the first is later. Line 3 gives sort a small arrow function that calls compare on each pair of dates. Line 4 prints the dates in order.

Date texts like these happen to sort in the right order too. But compare says clearly that you are comparing dates.

Why January 31 plus one month is February 29

February has no day 31. By default, Temporal picks the last real day of February instead. 2024 is a leap year, so February 2024 has 29 days. The answer is February 29.

PlainYearMonth & PlainMonthDay

Some dates are missing a part on purpose:

  • A credit card's end date has a year and a month, but no day.
  • A yearly birthday reminder has a month and a day, but no year.

Temporal has a type for each. So you don't have to make up a fake day or a fake year to fill a full date.

A month of a year, and a day of a monthPop out in the code editor (opens in a new tab)JavaScript
const expiry = Temporal.PlainYearMonth.from("2024-02");const leapBirthday = Temporal.PlainMonthDay.from("--02-29");console.log(expiry.toString());console.log(leapBirthday.toString());

Line 1 makes February 2024. Line 2 makes February 29 with no year. The two dashes in "--02-29" stand where the year would be.

Real-life analogyPointing at a paper calendar

When you talk about a paper calendar, you don't always point at one square. Sometimes you mean the whole month page. Sometimes you mean a day that comes back every year.

In real life: A whole page that says February 2024
In JavaScript: PlainYearMonth.from("2024-02")
In real life: The birthday square for Feb 29, any year
In JavaScript: PlainMonthDay.from("--02-29")
In real life: One square on one page: Feb 29, 2024
In JavaScript: PlainDate.from("2024-02-29")

ZonedDateTime & time zones

STEP THROUGH

An offset is how far a clock is from UTC, like -05:00 (five hours behind UTC). A time zone is more than one offset. It is a named set of rules, like America/New_York. The rules say:

  • which offset the place uses on each day
  • when the clocks move for summer time
  • how those rules changed in past years

Many places move their clocks forward one hour in spring and back one hour in autumn. This is called daylight saving time, or DST.

A ZonedDateTime keeps three things together:

  • one exact moment
  • the date and clock time people see in that place
  • the time zone's rules
Clock change: 24 hours or 1 day
Step 0 of 4Ready
Your turn: follow the blue line

A time zone is more than an offset. Step through to see why adding 24 hours and adding 1 day can give different clock times.

Running in
  1. script
Next: line 1
  "2024-03-10T01:30-05:00[America/New_York]",);console.log(beforeSpringForward.toString());console.log(beforeSpringForward.add({ hours: 24 }).toString());console.log(beforeSpringForward.add({ days: 1 }).toString());
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

In New York on March 10, 2024, the clocks jumped from 01:59:59 straight to 03:00:00. India doesn't use DST today. But an Indian app with users abroad still has to handle clock changes like this one.

Because of the jump, adding { hours: 24 } and adding { days: 1 } give different clock times in the example:

  • { hours: 24 } adds 24 real hours.
  • { days: 1 } moves to the same clock time on the next day.
New York, March 10, 2024, at 01:30. Adding 24 hours gives March 11 at 02:30. Adding 1 day gives March 11 at 01:30.Mar 10, 01:30New York+ 24 hoursMar 11, 02:3024 real hours later+ 1 dayMar 11, 01:30same clock time, next day
At 02:00 on March 10, 2024, New York clocks jumped forward to 03:00. So 24 real hours after 01:30, the clock reads 02:30 the next day. Adding 1 day keeps the same clock time, 01:30, and only 23 real hours pass.

In autumn, the clocks go back one hour. On November 3, 2024, New York saw 01:30 twice: once before the clocks went back, and once after. So "01:30 on November 3" could mean two different moments.

Disambiguation is how Temporal picks one. You tell it with the disambiguation option:

  • "earlier" picks the first 01:30.
  • "later" picks the second 01:30.
  • "reject" throws an error, so your app can ask the user to choose.
Pick one of two 01:30 meeting timesPop out in the code editor (opens in a new tab)JavaScript
const localMeeting = "2024-11-03T01:30[America/New_York]";const earlier = Temporal.ZonedDateTime.from(localMeeting, {  disambiguation: "earlier",});const later = Temporal.ZonedDateTime.from(localMeeting, {  disambiguation: "later",});console.log(earlier.toString());console.log(later.toString());

Line 1 is the meeting as text: the date, the clock time, and the time zone name in square brackets. This text format is a standard called RFC 9557. Lines 2 to 7 read the text twice, once with each choice:

  • The first output picks the earlier 01:30, with offset -04:00.
  • The second output picks the later 01:30, with offset -05:00.

Both show 01:30 on the clock. But they are two different moments, one hour apart.

Turn a form's date and time into a meetingPop out in the code editor (opens in a new tab)JavaScript
const date = Temporal.PlainDate.from("2024-05-12");const time = Temporal.PlainTime.from("09:30");const meeting = date.toPlainDateTime(time).toZonedDateTime("America/New_York");console.log(meeting.toString());console.log(meeting.toInstant().toString());
What the meeting code prints

2024-05-12T09:30:00-04:00[America/New_York]

2024-05-12T13:30:00Z

A form can ask for a date and a time without a place. Lines 1 and 2 hold those two answers. When the user picks a place, line 3 joins the date and time and adds the time zone with toZonedDateTime. Line 5 calls toInstant to get the exact moment, ready to save or send.

Duration & arithmetic

INTERACTIVE

A Duration is a length of time, like "3 days" or "1 hour 30 minutes". It is not a point in time. You can get one in two ways:

  • Measure between two values with until or since.
  • Build one yourself with Temporal.Duration.from.

You can also round a Duration, or turn it into one unit, like "90 minutes". You tell Temporal which unit you want.

Two date cards, Feb 28 and Mar 2. An arrow from start to end is labelled start.until(end). Below it, a card says P3D: a length of 3 days.Feb 28startstart.until(end)Mar 2endP3Da length: 3 days
The two dates are points on the calendar. until() measures the gap between them and gives back a Duration, a length of time. In 2024 the gap is 3 days: Feb 29, Mar 1, and Mar 2. P3D is how a Duration writes "3 days".
Run the Duration code
Measure a gap and a timerPop out in the code editor (opens in a new tab)JavaScript
const start = Temporal.PlainDate.from("2024-02-28");const end = Temporal.PlainDate.from("2024-03-02");const between = start.until(end);const timer = Temporal.Duration.from({ hours: 1, minutes: 30 });console.log(between.toString());console.log(between.days);console.log(timer.toString());console.log(timer.total({ unit: "minutes" }));
Console outputexample
  1. P3D
  2. 3
  3. PT1H30M
  4. 90
Try it yourself

Read the code and guess the four lines. Then run it.

until measures the gap between two dates and gives back a Duration. total turns a Duration into one unit.
Step through the Duration code
Step 0 of 6Ready
Your turn: follow the blue line

Two dates can give you a Duration. You can then turn a Duration into one unit, or round it.

Running in
  1. script
Next: line 1
const end = Temporal.PlainDate.from("2024-03-02");const between = start.until(end);const timer = Temporal.Duration.from({ hours: 1, minutes: 30 });console.log(between.toString());console.log(between.days);console.log(timer.toString());console.log(timer.total({ unit: "minutes" }));
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Rounding months needs a start date

An hour is always 60 minutes. But a month can have 28, 29, 30, or 31 days, and a year can have 365 or 366. So to round or total months and years, Temporal may need a start date. Then it knows which month or year you mean.

Round a duration and a clock timePop out in the code editor (opens in a new tab)JavaScript
const duration = Temporal.Duration.from({ minutes: 95 });console.log(duration.round({  largestUnit: "hours",  smallestUnit: "hours",  roundingMode: "halfExpand",}).toString());const time = Temporal.PlainTime.from("09:40");console.log(time.round({ smallestUnit: "hour", roundingMode: "halfExpand" }).toString());
What the rounding code prints

PT2H

10:00:00

Lines 2 to 6 round 95 minutes to whole hours. halfExpand is the rounding you learned at school: halfway or more rounds up. So 95 minutes (1 hour 35 minutes) becomes 2 hours, printed as PT2H. Line 8 uses the same rule on the clock time 09:40, which becomes 10:00. This helps when you show times in one-hour slots.

Count the gap in days or in monthsPop out in the code editor (opens in a new tab)JavaScript
const start = Temporal.PlainDate.from("2024-01-31");const end = Temporal.PlainDate.from("2024-03-31");console.log(start.until(end, { largestUnit: "days" }).toString());console.log(start.until(end, { largestUnit: "months" }).toString());console.log(end.since(start, { largestUnit: "months" }).toString());
What the gap code prints

P60D

P2M

P2M

largestUnit sets the biggest unit the answer may use. The same two dates give two answers:

  • With "days", line 3 prints P60D: 60 days.
  • With "months", line 4 prints P2M: 2 months.

Line 5 uses since, which measures from the other end, and also prints P2M. Pick the unit your app shows to its users.

Calendars

A calendar is a system for naming days: which year, which month, which day. Most of the world uses the Gregorian calendar. Others include the Hebrew and Japanese calendars.

Temporal uses the ISO calendar by default. That is the Gregorian calendar, written the way computers usually write it, like 2024-05-01. But a Temporal date can also use another calendar. The day stays the same; only its name changes.

Show a date in the Japanese calendarPop out in the code editor (opens in a new tab)JavaScript
const isoDate = Temporal.PlainDate.from("2024-05-01");const japaneseDate = isoDate.withCalendar("japanese");console.log(japaneseDate.toString());
What the calendar code prints (from a browser with Temporal)

2024-05-01[u-ca=japanese]

Line 2 switches the date to the Japanese calendar. Line 3 prints it. The text in square brackets, [u-ca=japanese], is a note that says which calendar the date uses.

Japanese era names, and how dates look in other languages, depend on data inside each browser. So this lesson only shows the output our tests check: the date with its calendar note.

A calendar and a time zone answer different questions:

  • A calendar answers: "Which year, month, and day is this?"
  • A time zone answers: "What does the clock show in this place at this moment?"

Switching to the Japanese calendar doesn't move the moment, and it doesn't change the time zone.

Migrating from Date

INTERACTIVE

To move old Date code to Temporal, first ask: "What kind of time do I really have?"

  • An exact moment? Turn it into an Instant.
  • A date from a form? Read it as a PlainDate.
  • A flight or a meeting in a place? Use a type with a time zone, ZonedDateTime.

In the table, each row is one common Date habit. Read across to see what to use instead, and why.

Old Date code and what to use in Temporal
When you used to writeWrite this insteadWhy it's clearer
Date.now()Temporal.Now.instant()You get an exact moment with a name, not just a number.
new Date(y, m, d)Temporal.PlainDate.from({ year, month, day })Months start at 1, and the type says there is no time zone.
date.toISOString()instant.toString()An Instant already prints as standard date text ending in Z.
date.setDate(date.getDate() + 1)plainDate.add({ days: 1 })It makes a new date. The old one stays the same.
date.getTime()instant.epochMillisecondsThe milliseconds number is a named property of the Instant.
Turn a Date into an Instant
Turn a Date's milliseconds into an InstantPop out in the code editor (opens in a new tab)JavaScript
const legacyDate = new Date("2024-03-10T06:30:00.000Z");const instant = Temporal.Instant.fromEpochMilliseconds(legacyDate.getTime());console.log(instant.toString());console.log(instant.epochMilliseconds);
Console outputexample

2024-03-10T06:30:00Z

1710052200000

Try it yourself

A Date holds one exact moment. Turn that moment into an Instant first. Change it into a date or a time in a place later, on purpose.

This page never loads extra code to add Temporal. If your browser doesn't have it, the output is an example, checked by our tests.
Turn a date into text for savingPop out in the code editor (opens in a new tab)JavaScript
const dueDate = Temporal.PlainDate.from("2024-05-12");console.log(JSON.stringify(dueDate));console.log(dueDate.toString({ calendarName: "never" }));

Before you save or send a value, you turn it into text. Line 2 does this with JSON.stringify and prints "2024-05-12", a date with no time added. Line 3 gets the same date text with toString. The option { calendarName: "never" } says: don't add a calendar note.

Save the value just as it is. Add a time zone later, only when you really have a place and a clock time.

A practical scheduling decision

When you build a form or a database field, don't start from "Which date method do I know?". Start from "What did the user actually type in?"

  • A birthday reminder needs a month and a day that come back every year.
  • A card's end date needs a year and a month.
  • A meeting invitation needs a clock time and a named time zone.
  • A server log needs one exact moment.

In the table, find what your app receives in the first column. The second column is the type to use.

Which Temporal type fits what your app receives
What your app receivesType to useWhy
A log line ending in ZInstantIt already names one exact moment.
A birthday form with a month and a dayPlainMonthDayThe reminder comes back every year.
A card end date such as 2028-04PlainYearMonthThere is no day on purpose.
A meeting at 09:00 in a named time zoneZonedDateTimeThe clock time and the place's rules both matter.

Keeping the types apart also helps when you save them:

  • Save an Instant as date text or as its milliseconds number.
  • Save a PlainDate as date-only text.
  • Save a future meeting with its time zone name next to it.

Don't turn every value into "midnight UTC" just to fit one old database field.

Show a date and a time to a readerPop out in the code editor (opens in a new tab)JavaScript
const date = Temporal.PlainDate.from("2024-05-12");const time = Temporal.PlainTime.from("09:30");console.log(date.toLocaleString("en-GB"));console.log(time.toLocaleString("en-GB"));
What the display code prints

12/05/2024

09:30:00

A locale is a language and region code, like "en-GB" for British English. It decides how dates look, for example day first or month first. Lines 3 and 4 pass "en-GB", so the date shows day first.

toLocaleString makes text for people to read. Don't save that text. Keep the Temporal value, and turn it into display text again whenever you need it.

Common misconceptions

“Temporal works in every browser now.”

Not yet. Check for it first. This lesson never loads extra code to add Temporal, and it labels example output when your browser doesn't have it.

“A PlainDate is a date at midnight.”

No. A PlainDate has no clock time and no time zone. "Midnight" would need a place: midnight where?

“A time zone is just an offset.”

An offset is one number, right for one moment. A named time zone has rules, and its offset can change during the year.

“add({ days: 1 }) and add({ hours: 24 }) always give the same result.”

Not on a ZonedDateTime on a day when the clocks change. The New York example shows them landing at different clock times.

“Temporal values change, like Date does.”

No. Temporal methods give back new values. The original stays the same, unless you put a new value in its variable yourself.

“Two equal dates are equal with ===.”

Two dates made separately are two separate objects, so === says false. Use equals to compare the dates themselves. And keep the result of add in a variable.

Compare two dates, and keep the new datePop out in the code editor (opens in a new tab)JavaScript
const first = Temporal.PlainDate.from("2024-05-12");const second = Temporal.PlainDate.from("2024-05-12");console.log(first === second);console.log(first.equals(second));const due = first.add({ days: 1 });console.log(first.toString());console.log(due.toString());
What the compare code prints

false

true

2024-05-12

2024-05-13

Line 3 asks, "Are these the same object?" They aren't, so === prints false. Line 4 asks, "Are these the same date?" They are, so equals prints true. Line 5 keeps the new date from add in due. Line 6 shows that first didn't change. Line 7 prints the new date.

Some Temporal types sound alike. Each row of the table is one type: what it holds, and when to use it.

Temporal types that are easy to mix up
TypeWhat it holdsWhen to use it
InstantOne exact moment.Logs, the moment something runs out, and times from old Date code.
PlainDateA year, a month, a day, and a calendar.Birthdays, due dates, and dates typed into forms.
PlainTimeAn hour, a minute, and a second.Daily alarms and opening times.
ZonedDateTimeAn exact moment, plus the clock time and time zone of a place.Flights, meetings, and deadlines in a place.
DurationA length of time.Countdowns, gaps between dates, and date math.

Practice: Temporal

5 EXERCISES
Exercise 1 · Warm-upPredict January 31 plus one month

Read the code. What does the first line of output say?

Starter codePop out in the code editor (opens in a new tab)JavaScript
const original = Temporal.PlainDate.from("2024-01-31");
const later = original.add({ months: 1 });
const firstDay = original.with({ day: 1 });
console.log(later.toString());
console.log(firstDay.toString());
console.log(original.toString());
console.log(Temporal.PlainDate.compare(original, later));
console.log(original.equals(Temporal.PlainDate.from("2024-01-31")));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeChoose the right type

    Which Temporal type fits a server log time such as 2024-03-10T06:30:00Z?

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeCount the days between two dates

      How many days are there between the two dates?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const start = Temporal.PlainDate.from("2024-02-28");
      const end = Temporal.PlainDate.from("2024-03-02");
      const between = start.until(end);
      const timer = Temporal.Duration.from({ hours: 1, minutes: 30 });
      console.log(between.toString());
      console.log(between.days);
      console.log(timer.toString());
      console.log(timer.total({ unit: "minutes" }));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeTurn a Date into an Instant

        What Instant text does this code print first?

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const legacyDate = new Date("2024-03-10T06:30:00.000Z");
        const instant = Temporal.Instant.fromEpochMilliseconds(legacyDate.getTime());
        console.log(instant.toString());
        console.log(instant.epochMilliseconds);

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeFix a bug where Date changes by mistake

          Rewrite the code with Temporal so the start date doesn't change. What due date prints?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const start = new Date("2024-01-31T00:00:00.000Z");
          const due = start;
          due.setUTCMonth(due.getUTCMonth() + 1);
          console.log(start.toISOString()); // start changed too

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            7 QUESTIONS

            For each question, first ask: "What kind of time is this: an exact moment, a plain date or time, a time in a place, or a length of time?" Each answer explains why it is right or wrong.

            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7Which Temporal type means one exact moment, the same everywhere on Earth?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does this print first?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const date = Temporal.PlainDate.from("2024-01-31");
              console.log(date.add({ months: 1 }).toString());

              Choose an answer to see the explanation.

            3. Question 3 of 7Which type fits the end date on a credit card, like 04/28?

              Choose an answer to see the explanation.

            4. Question 4 of 7On a day when the clocks change, why can adding { hours: 24 } give a different result from adding { days: 1 }?

              Choose an answer to see the explanation.

            5. Question 5 of 7What does this print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const timer = Temporal.Duration.from({ hours: 1, minutes: 30 });
              console.log(timer.total({ unit: "minutes" }));

              Choose an answer to see the explanation.

            6. Question 6 of 7Which sentence about calendars is true?

              Choose an answer to see the explanation.

            7. Question 7 of 7How do you turn an old Date into a Temporal Instant?

              Choose an answer to see the explanation.

            Key takeaways

            • Temporal is a toolbox: one type for each time job, instead of one Date object for everything.
            • An Instant is one exact moment. The Plain types are dates or clock times with no time zone.
            • A ZonedDateTime knows its place's clock rules, so on a clock-change day, 24 hours and 1 day can be different.
            • A Duration is a length of time. You can round it, or turn it into one unit like minutes.
            • Temporal values never change. To move from Date, start by turning its milliseconds number into an Instant.

            Remember the one-liner.
            Pick the Temporal type that matches your time data. Then let its methods do the date math, without changing the original.

            Up next: Number & Math in depth.

            CompleteFrontend Clear concepts. Working examples.