Skip to content

Date and time formatting

Source URL: https://next-intl.dev/docs/usage/dates-times

DocsUsage guideDates and times

Prefer to watch a video?

Date formatting

The formatting of dates and times varies greatly between locales (e.g. “Apr 24, 2023” in en-US vs. “24 квіт. 2023 р.” in uk-UA). By using the formatting capabilities of next-intl, you can handle i18n differences in your Next.js app automatically.

You can format plain dates that are not part of a message with the dateTime function that is returned from the useFormatter hook:

import {useFormatter} from 'next-intl';
function Component() {
const format = useFormatter();
const dateTime = new Date('2020-11-20T10:36:01.516Z');
// Renders "Nov 20, 2020"
format.dateTime(dateTime, {
year: 'numeric',
month: 'short',
day: 'numeric'
});
// Renders "11:36 AM"
format.dateTime(dateTime, {hour: 'numeric', minute: 'numeric'});
}

See the MDN docs on DateTimeFormat to learn more about the options that you can provide to the dateTime function or try the interactive explorer for Intl.DateTimeFormat.

If you have global formats configured, you can reference them by passing a name as the second argument:

// Use a global format
format.dateTime(dateTime, 'short');
// Optionally override some options
format.dateTime(dateTime, 'short', {year: 'numeric'});

How should I store and parse dates and time zones?

You should ensure that dates are full ISO 8601 strings, e.g. 2020-11-20T10:36:01.516Z.

Since next-intl is only concerned with formatting dates, you can use the Date constructor to parse them before formatting them in the frontend.

Learn more:

Dates & time zones

You can format plain dates that are not part of a message with the relativeTime function:

import {useFormatter} from 'next-intl';
function Component() {
const format = useFormatter();
const dateTime = new Date('2020-11-20T08:30:00.000Z');
// A reference point in time
const now = new Date('2020-11-20T10:36:00.000Z');
// This will render "2 hours ago"
format.relativeTime(dateTime, now);
}

Note that values are rounded, so e.g. if 126 minutes have passed, “2 hours ago” will be returned.

Learn more:

Relative times

Since providing now is a common pattern, next-intl provides a convenience hook that can be used to retrieve the current date and time:

import {useNow, useFormatter} from 'next-intl';
function FormattedDate({date}) {
const now = useNow();
const format = useFormatter();
format.relativeTime(date, now);
}

In contrast to simply calling new Date() in your component, useNow has some benefits:

  1. The returned value is consistent across re-renders on the client side.
  2. You can optionally use updateInterval to update the value continuously.
  3. The value can optionally be initialized from a global value. By default, useNow will use the current time.

In case you want a relative time value to update over time, you can do so with the useNow hook:

import {useNow, useFormatter} from 'next-intl';
function Component() {
// Use the global now value initially …
const now = useNow({
// … and update it every 10 seconds
updateInterval: 1000 * 10
});
const format = useFormatter();
const dateTime = new Date('2020-11-20T10:36:01.516Z');
// Renders e.g. "2 hours ago" and updates continuously
format.relativeTime(dateTime, now);
}

By default, relativeTime will pick a unit based on the difference between the passed date and now like “3 seconds” or “5 days”.

If you want to use a specific unit, you can provide options via the second argument:

import {useFormatter} from 'next-intl';
function Component() {
const format = useFormatter();
const dateTime = new Date('2020-03-20T08:30:00.000Z');
const now = new Date('2020-11-22T10:36:00.000Z');
// Renders "247 days ago"
format.relativeTime(dateTime, {now, unit: 'day'});
}

You can format ranges of dates and times with the dateTimeRange function:

import {useFormatter} from 'next-intl';
function Component() {
const format = useFormatter();
const dateTimeA = new Date('2020-11-20T08:30:00.000Z');
const dateTimeB = new Date('2021-01-24T08:30:00.000Z');
// Renders "Nov 20, 2020 – Jan 24, 2021"
format.dateTimeRange(dateTimeA, dateTimeB, {
year: 'numeric',
month: 'short',
day: 'numeric'
});
}

If you have global formats configured, you can reference them by passing a name as the third argument:

// Use a global format
format.dateTimeRange(dateTimeA, dateTimeB, 'short');
// Optionally override some options
format.dateTimeRange(dateTimeA, dateTimeB, 'short', {year: 'numeric'});

Dates and times can be embedded within messages by using the ICU syntax.

en.json

{
"ordered": "Ordered on {orderDate, date, medium}"
}

These formats are supported out of the box: full, long, medium and short.

💡

If you work with translators, it can be helpful for them to use an editor that supports the ICU syntax for dates and times (e.g. the Crowdin Editor).

You can customize the formatting by using date skeletons:

en.json

{
// Renders e.g. "Ordered on Jul 9, 2024"
"ordered": "Ordered on {orderDate, date, ::yyyyMMMd}"
}

Note the leading :: that is used to indicate that a skeleton should be used.

These formats from ICU are supported:

SymbolMeaningPatternExample
GEra designator (includes the date)G
GGGG
GGGGG7/9/2024 AD
7/9/2024 Anno Domini
7/9/2024 A
yYeary
yy
yyyy2024
24
2024
MMonth in yearM
MM
MMM
MMMM
MMMMM
7
07
Jul
July
J
dDay in monthd
dd9
09
EDay of weekE
EEEE
EEEEETue
Tuesday
T
hHour (1-12)h
hh9 AM
09 AM
KHour (0-11)K
KK0 AM (12 AM with h)
00 AM
HHour (0-23)HH09
kHour (1-24)kk24 (00 with H)
mMinute (2 digits if used with seconds)m
mmss6
06:03
sSecond (2 digits if used with minutes)s
mmss3
06:03
zTime zonez
zzzzGMT+2
Central European Summer Time

Patterns can be combined with each other, therefore e.g. yyyyMMMd would return “Jul 9, 2024”.

To use custom formats in messages, you can provide formatters based on DateTimeFormat options that can be referenced by name.

en.json

{
"ordered": "Ordered on {orderDate, date, short}"
}
t(
'ordered',
{orderDate: new Date('2020-11-20T10:36:01.516Z')},
{
dateTime: {
short: {
day: 'numeric',
month: 'short',
year: 'numeric'
}
}
}
);

💡

To reuse date and time formats for multiple components, you can configure global formats.