Skip to content
next-intl 3.0 is out! (announcement)
Docs
Usage guide
Dates and times

Date and time 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.

Formatting dates and times

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 about DateTimeFormat (opens in a new tab) to learn more about the options that you can provide to the dateTime function or try the interactive explorer for Intl.DateTimeFormat (opens in a new tab).

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

format.dateTime(dateTime, 'short');
How can I parse dates or manipulate them?

Since next-intl is only concerned with formatting dates, you can use a library like date-fns (opens in a new tab) to manipulate them.

To parse dates, you can pass them to the Date constructor (opens in a new tab).

import {subDays} from 'date-fns';
 
// Make sure your date string conforms to ISO 8601
const date = new Date('2020-11-20T10:36:01.516Z');
 
// 2020-11-18T10:36:01.516Z
const twoDaysAgo = subDays(date, 2);

Formatting relative times

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');
 
  // At 2020-11-20T10:36:00.000Z,
  // this will render "2 hours ago"
  format.relativeTime(dateTime);
}

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

Supplying now

By default, relativeTime will use the global value for now. If you want to use a different value, you can explicitly pass this as the second parameter.

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

If you want the 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);
}

Customizing the unit

By default, relativeTime will pick a unit based on the difference between the passed date and now (e.g. 3 seconds, 40 minutes, 4 days, etc.).

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'});
}

Formatting date and time ranges

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 trailing argument:

format.dateTimeRange(dateTimeA, dateTimeB, 'short');

Dates and times within messages

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 (opens in a new tab)).

You can customize the formatting by using date skeletons:

en.json
{
  "ordered": "Ordered on {orderDate, date, ::yyyyMd}"
}

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

These formats from ICU are supported:

SymbolMeaning
GEra designator
yYear
MMonth in year
LStand-alone month in year
dDay in month
EDay of week
eLocal day of week
cStand-alone local day of week
aAM/PM marker
hHour [1-12]
HHour [0-23]
KHour [0-11]
kHour [1-24]
mMinute
sSecond
zTime zone

Custom date and time formats

To use custom formats in messages, you can provide formatters based on DateTimeFormat options (opens in a new tab) 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.