How to display AM/PM or locale-specific day periods
Use JavaScript to show time periods that match each culture's way of dividing the day
Introduction
When you display a time like 4:00, users need context to know whether it occurs in the morning or afternoon. In English, you add AM or PM to clarify. 4:00 AM happens before sunrise, while 4:00 PM happens in the afternoon.
Other languages do not simply translate AM and PM. Many cultures divide the day into more than two periods, with specific terms for early morning, late morning, afternoon, evening, and night. Spanish has "madrugada" for the hours after midnight but before dawn. German divides the day into six distinct periods instead of two. Some languages call 1:00 AM "1 at night" rather than "1 in the morning".
JavaScript's Intl.DateTimeFormat provides the dayPeriod option to display these culture-specific time divisions automatically. This lesson explains how day periods work across cultures, why they matter for international applications, and how to format times with appropriate day period labels.
Why day periods vary by culture
Different cultures developed different ways of dividing the 24-hour day into named periods. These divisions reflect how people in each culture think about and talk about time.
English speakers divide the day into four periods. Morning runs from midnight to noon, afternoon from noon to evening, evening from late afternoon until dark, and night from dark until midnight. The terms AM and PM provide a simpler two-period system for the 12-hour clock.
Spanish speakers recognize "madrugada" as a distinct period covering the hours after midnight but before people typically wake up. This creates a five-period system that distinguishes between late night hours and early morning hours.
Russian speakers use "ночь" (night) to refer to any hour when people are typically asleep. 1:00 AM is "1 at night" rather than "1 in the morning" because people are normally sleeping at that hour.
German divides the day into six periods. "Morgen" (morning), "Vormittag" (forenoon), "Mittag" (midday), "Nachmittag" (afternoon), "Abend" (evening), and "Nacht" (night) each cover specific ranges of hours.
Indonesian uses "pagi" (dawn to 10 AM), "siang" (10 AM to 2 PM), "sore" (2 PM to sunset), and "malam" (night) to divide the day into four periods based on the position of the sun.
Bengali divides the day into six periods. "ভোর" (dawn), "সকাল" (morning), "দুপুর" (early afternoon), "বিকাল" (late afternoon), "সন্ধ্যা" (evening), and "রাত" (night) each have specific time ranges.
When you display times in an international application, you need to use terms that match how users in each culture naturally talk about time. Showing "4 AM" to all users ignores how other languages describe that hour.
Understanding the dayPeriod option
The dayPeriod option in Intl.DateTimeFormat tells the formatter to include the locale-specific day period when formatting a time. Instead of displaying just the hour and minute, the formatter adds the appropriate term for that time of day in the target language.
This option works only with 12-hour time formats. In 24-hour formats, the hour number itself provides enough context. 04:00 is clearly morning and 16:00 is clearly afternoon without additional labels. Day periods exist to disambiguate the repeated hours in 12-hour format.
The dayPeriod option accepts three values. narrow produces the shortest possible form, often a single letter or abbreviation. short produces an abbreviated form. long produces the full word or phrase.
For many locales, these three values produce identical output. The Unicode locale data does not define distinct forms for every combination of locale and format length. When distinct forms do not exist, the formatter uses the same output regardless of which value you specify.
Formatting times with day periods
To display a day period, create an Intl.DateTimeFormat instance with the dayPeriod option set to narrow, short, or long. You must also include a time component option like hour and specify a 12-hour format using hourCycle.
const date = new Date('2025-01-15T04:30:00');
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(formatter.format(date));
// Output: "4:30 in the morning"
This creates a formatter that displays the hour, minute, and day period. The hourCycle: 'h12' option specifies 12-hour format, which is required for day periods to appear. The dayPeriod: 'long' option requests the full day period phrase.
Without the dayPeriod option, the formatter would display "4:30 AM" instead. The day period option replaces the simple AM/PM indicator with a more descriptive phrase.
Displaying day periods across different times
Day periods change based on the time being formatted. The formatter automatically selects the appropriate period for each time according to the locale's conventions.
const options = {
hour: 'numeric',
minute: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
};
const formatter = new Intl.DateTimeFormat('en-US', options);
const morning = new Date('2025-01-15T04:30:00');
console.log(formatter.format(morning));
// Output: "4:30 in the morning"
const afternoon = new Date('2025-01-15T14:30:00');
console.log(formatter.format(afternoon));
// Output: "2:30 in the afternoon"
const evening = new Date('2025-01-15T20:30:00');
console.log(formatter.format(evening));
// Output: "8:30 in the evening"
const night = new Date('2025-01-15T23:30:00');
console.log(formatter.format(night));
// Output: "11:30 at night"
English distinguishes between morning, afternoon, evening, and night. Each time receives the appropriate phrase based on the hour. You do not need to determine which period applies. The formatter handles this automatically based on Unicode locale data.
Comparing narrow, short, and long formats
The three format lengths produce different outputs in some locales. The differences vary by language and may be subtle or nonexistent.
const date = new Date('2025-01-15T04:30:00');
const narrow = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'narrow'
});
console.log(narrow.format(date));
// Output: "4 in the morning"
const short = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'short'
});
console.log(short.format(date));
// Output: "4 in the morning"
const long = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(long.format(date));
// Output: "4 in the morning"
For US English, all three lengths produce identical output. The locale data does not define different forms for this combination of language and time.
Some locales do distinguish between lengths. French produces different outputs for narrow and long formats.
const date = new Date('2025-01-15T04:30:00');
const frNarrow = new Intl.DateTimeFormat('fr-FR', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'narrow'
});
console.log(frNarrow.format(date));
// Output: "4 mat."
const frLong = new Intl.DateTimeFormat('fr-FR', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(frLong.format(date));
// Output: "4 du matin"
French uses "mat." as the abbreviated form and "du matin" as the long form. Both mean morning, but the long form is more explicit.
Unless you have specific space constraints requiring the shortest possible output, use long for clarity. The longer forms are easier for users to understand, and many locales do not provide shorter alternatives anyway.
How day periods work across locales
Different locales use different day period terms and divide the day at different boundaries. The formatter automatically applies the conventions for each locale.
const date = new Date('2025-01-15T04:30:00');
const options = {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
};
const enUS = new Intl.DateTimeFormat('en-US', options);
console.log(enUS.format(date));
// Output: "4 in the morning"
const enGB = new Intl.DateTimeFormat('en-GB', options);
console.log(enGB.format(date));
// Output: "4 at night"
const deDK = new Intl.DateTimeFormat('de-DE', options);
console.log(deDK.format(date));
// Output: "4 morgens"
const fr = new Intl.DateTimeFormat('fr-FR', options);
console.log(fr.format(date));
// Output: "4 du matin"
British English considers 4:30 AM to be "at night" rather than "in the morning", reflecting different cultural boundaries for day periods. German uses "morgens" for morning hours. French uses "du matin" for the same period.
These differences are not mistakes or inconsistencies. They reflect genuine cultural differences in how people conceptualize and talk about time. The formatter respects these differences automatically based on the locale.
Day periods require 12-hour format
The dayPeriod option only works when you specify a 12-hour format using hourCycle: 'h12' or hourCycle: 'h11'. Without a 12-hour format, day periods do not appear.
const date = new Date('2025-01-15T04:30:00');
const with12Hour = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(with12Hour.format(date));
// Output: "4 in the morning"
const with24Hour = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h23',
dayPeriod: 'long'
});
console.log(with24Hour.format(date));
// Output: "04"
The 24-hour format does not display the day period even though the option is specified. In 24-hour format, the hour number provides sufficient context without additional labels.
The difference between h12 and h11 relates to how midnight and noon are numbered. Use h12 for the standard 12-hour clock where hours go from 1 to 12. Use h11 for a 0-to-11 hour system. Both work with day periods.
Combining day periods with minutes and seconds
You can include minutes and seconds along with day periods. The formatter positions the day period appropriately according to the locale's conventions.
const date = new Date('2025-01-15T04:30:45');
const withMinutes = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(withMinutes.format(date));
// Output: "4:30 in the morning"
const withSeconds = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(withSeconds.format(date));
// Output: "4:30:45 in the morning"
The day period appears after the time components. You do not need to manually position or format the day period. The formatter handles the layout according to locale conventions.
Formatting times with day periods for the user's locale
Instead of hardcoding a specific locale, use the user's preferred language from the browser. The navigator.language property returns the user's top language preference.
const date = new Date('2025-01-15T04:30:00');
const formatter = new Intl.DateTimeFormat(navigator.language, {
hour: 'numeric',
minute: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(formatter.format(date));
// Output varies by user's locale
// For en-US: "4:30 in the morning"
// For en-GB: "4:30 at night"
// For de-DE: "4:30 morgens"
// For fr-FR: "4:30 du matin"
This approach displays times with day periods that match how each user naturally talks about time. The browser provides the language preference, and the Intl API applies the appropriate day period terms and boundaries.
When to use day periods
Day periods work well when you want to provide more context than simple AM/PM indicators. They make times more conversational and easier to interpret at a glance.
Use day periods in user interfaces where times appear alongside descriptive text. A calendar showing "4:30 in the morning" is clearer than "4:30 AM" because the phrase sounds more natural in running text.
Use day periods in notifications and messages where conversational language improves readability. "Your meeting starts at 8:30 in the evening" reads better than "Your meeting starts at 8:30 PM".
Avoid day periods in compact displays where space is limited. Tables, charts, and dense layouts work better with standard AM/PM indicators or 24-hour format.
Avoid day periods when displaying times in 24-hour format. The day period adds no useful information when the hour number already indicates the time of day.
Summary
The dayPeriod option in Intl.DateTimeFormat displays culture-specific terms for times of day. Different cultures divide the day differently, using terms like "madrugada" in Spanish or six distinct periods in German instead of just AM and PM.
The option accepts three values. narrow produces the shortest form, short produces an abbreviated form, and long produces the full phrase. Many locales produce identical output for all three values.
Day periods only appear when using 12-hour format specified with hourCycle: 'h12' or hourCycle: 'h11'. They do not appear in 24-hour format because the hour number provides sufficient context.
Different locales use different day period terms and draw boundaries at different hours. The formatter applies these conventions automatically based on the locale identifier. British English treats 4:30 AM as "at night" while American English treats it as "in the morning".