Как отображать AM/PM или локализованные периоды дня
Используйте JavaScript, чтобы показывать периоды времени в соответствии с тем, как каждая культура делит день
Введение
Когда вы показываете время, например 4:00, пользователям нужен контекст, чтобы понять, происходит это утром или днём. В английском для этого добавляют AM или PM. 4:00 AM — это до рассвета, а 4:00 PM — это днём.
В других языках AM и PM не просто переводятся. Во многих культурах день делится не на две, а на несколько частей, и для каждой есть свои названия: раннее утро, позднее утро, день, вечер, ночь. Например, в испанском есть «madrugada» — это время после полуночи, но до рассвета. В немецком день делится на шесть периодов, а не на два. В некоторых языках 1:00 AM называют «1 час ночи», а не «1 час утра».
В JavaScript Intl.DateTimeFormat предоставляет опцию dayPeriod, чтобы автоматически отображать такие культурно-специфичные деления дня. В этом уроке объясняется, как устроены периоды дня в разных культурах, почему это важно для международных приложений и как форматировать время с правильными метками периода дня.
Почему периоды дня различаются в разных культурах
В разных культурах сложились свои способы деления 24-часового дня на периоды с названиями. Эти деления отражают то, как люди в каждой культуре воспринимают и обсуждают время.
Англоговорящие делят день на четыре периода. Утро длится с полуночи до полудня, день — с полудня до вечера, вечер — с позднего дня до темноты, а ночь — с темноты до полуночи. AM и PM — это более простая система из двух периодов для 12-часового формата.
Испаноязычные выделяют «madrugada» как отдельный период, охватывающий часы после полуночи, но до того, как люди обычно просыпаются. Это создает систему из пяти периодов, где поздняя ночь и раннее утро различаются.
Русскоязычные используют «ночь» для обозначения любого времени, когда люди обычно спят. 1:00 — это «час ночи», а не «час утра», потому что в это время обычно спят.
В немецком языке день делится на шесть периодов: «Morgen» (утро), «Vormittag» (до полудня), «Mittag» (полдень), «Nachmittag» (после полудня), «Abend» (вечер) и «Nacht» (ночь), каждый из которых охватывает определённые часы.
В индонезийском языке день делится на четыре периода: «pagi» (от рассвета до 10 утра), «siang» (с 10 до 14), «sore» (с 14 до заката) и «malam» (ночь) — всё это основано на положении солнца.
В бенгальском языке день делится на шесть периодов: «ভোর» (рассвет), «সকাল» (утро), «দুপুর» (ранний день), «বিকাল» (поздний день), «সন্ধ্যা» (вечер) и «রাত» (ночь), каждый из которых имеет свои временные рамки.
Когда вы отображаете время в международном приложении, важно использовать термины, которые соответствуют тому, как пользователи в разных культурах обычно говорят о времени. Показывать всем пользователям «4 AM» — значит игнорировать, как другие языки описывают этот час.
Понимание опции dayPeriod
Опция dayPeriod в Intl.DateTimeFormat указывает форматтеру включать локализованный период дня при форматировании времени. Вместо того чтобы показывать только часы и минуты, форматтер добавляет подходящее обозначение времени суток на целевом языке.
Эта опция работает только с 12-часовым форматом времени. В 24-часовом формате сам номер часа даёт достаточно контекста: 04:00 — это явно утро, а 16:00 — явно день, без дополнительных меток. Периоды дня нужны, чтобы различать повторяющиеся часы в 12-часовом формате.
Опция dayPeriod принимает три значения. narrow выдаёт самую короткую форму, часто это одна буква или аббревиатура. short выдаёт сокращённую форму. long выдаёт полное слово или фразу.
Во многих локалях эти три значения дают одинаковый результат. Unicode-данные локали не определяют отдельные формы для каждой комбинации языка и длины формата. Если отдельные формы не предусмотрены, форматтер использует одинаковый вывод независимо от выбранного значения.
Форматирование времени с учётом периодов дня
Чтобы отобразить период дня, создайте экземпляр Intl.DateTimeFormat с опцией dayPeriod, установленной в narrow, short или long. Также нужно добавить опцию времени, например hour, и указать 12-часовой формат через 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"
Это создаёт форматтер, который отображает часы, минуты и период дня. Опция hourCycle: 'h12' задаёт 12-часовой формат, что обязательно для отображения периодов дня. Опция dayPeriod: 'long' запрашивает полную фразу периода дня.
Без опции dayPeriod форматтер бы показал просто «4:30 AM». Опция периода дня заменяет обычный индикатор AM/PM на более подробную фразу.
Отображение периодов дня в разное время
Периоды дня меняются в зависимости от форматируемого времени. Форматтер автоматически выбирает подходящий период для каждого времени согласно правилам локали.
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"
В английском языке различают утро, день, вечер и ночь. Каждое время получает соответствующую фразу в зависимости от часа. Не нужно самостоятельно определять, какой период подходит — форматтер делает это автоматически на основе данных Unicode по локали.
Сравнение узких, коротких и длинных форматов
Три варианта длины формата дают разные результаты в некоторых локалях. Отличия зависят от языка и могут быть едва заметными или вовсе отсутствовать.
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"
Для американского английского все три варианта дают одинаковый результат. В данных локали не определены разные формы для этой комбинации языка и времени.
В некоторых локалях различают длины форматов. Например, во французском языке узкий и длинный форматы отличаются.
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"
Во французском используется «mat.» как сокращённая форма и «du matin» как длинная форма. Обе означают «утро», но длинная форма более явная.
Если нет строгих ограничений по месту и не требуется самый короткий вариант, используйте long для ясности. Длинные формы проще для понимания, а во многих локалях коротких вариантов вообще нет.
Как работают периоды дня в разных локалях
В разных локалях используются разные обозначения периодов дня и разные границы между ними. Форматтер автоматически применяет нужные правила для каждой локали.
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"
В британском английском 4:30 утра считается «ночью», а не «утром», что отражает культурные различия в определении периодов дня. В немецком для утренних часов используется «morgens». Во французском — «du matin».
Эти различия — не ошибки и не несогласованности. Они отражают реальные культурные особенности восприятия и описания времени. Форматтер автоматически учитывает эти различия в зависимости от локали.
Для периодов дня нужен 12-часовой формат
Опция dayPeriod работает только при указании 12-часового формата через hourCycle: 'h12' или hourCycle: 'h11'. Без 12-часового формата периоды дня не отображаются.
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"
В 24-часовом формате период дня не отображается, даже если эта опция указана. В этом формате номер часа уже даёт достаточно контекста, дополнительные метки не нужны.
Разница между h12 и h11 связана с тем, как обозначаются полночь и полдень. Используйте h12 для стандартных 12-часовых часов, где часы идут от 1 до 12. Используйте h11 для системы с часами от 0 до 11. Оба варианта поддерживают периоды дня.
Комбинирование периодов дня с минутами и секундами
Можно добавить минуты и секунды вместе с периодами дня. Форматтер сам разместит период дня в соответствии с правилами выбранной локали.
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"
Период дня появляется после компонентов времени. Не нужно вручную размещать или форматировать период дня — форматтер сам всё расставит по правилам локали.
Форматирование времени с периодами дня для локали пользователя
Вместо жёсткой привязки к определённой локали используйте предпочтительный язык пользователя из браузера. Свойство navigator.language возвращает основной языковой приоритет пользователя.
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"
Такой подход показывает время с периодами дня так, как это привычно для каждого пользователя. Браузер предоставляет языковые предпочтения, а Intl API применяет подходящие термины и границы периодов дня.
Когда использовать периоды дня
Периоды дня отлично подходят, если нужно дать больше контекста, чем просто AM/PM. Они делают отображение времени более разговорным и понятным с первого взгляда.
Используйте периоды дня в интерфейсах, где время показывается вместе с описательным текстом. Например, календарь с надписью «4:30 утра» выглядит понятнее, чем просто «4:30 AM», потому что такая фраза звучит естественнее в тексте.
Используйте периоды дня в уведомлениях и сообщениях, где разговорный стиль делает текст более понятным. «Ваша встреча начнётся в 8:30 вечера» звучит естественнее, чем «Ваша встреча начнётся в 8:30 PM».
Избегайте использования периодов дня в компактных интерфейсах, где пространство ограничено. В таблицах, графиках и плотных макетах лучше использовать стандартные обозначения AM/PM или 24-часовой формат.
Не используйте периоды дня при отображении времени в 24-часовом формате. В этом случае период дня не несёт полезной информации, так как номер часа уже указывает на время суток.
Итоги
Опция dayPeriod в Intl.DateTimeFormat отображает культурно-специфичные обозначения времени суток. В разных культурах день делится по-разному: например, в испанском есть «madrugada», а в немецком — шесть разных периодов вместо просто AM и PM.
Опция принимает три значения. narrow выдаёт самую короткую форму, short — сокращённую, а long — полную фразу. Во многих локалях все три значения дают одинаковый результат.
Периоды дня отображаются только при использовании 12-часового формата, заданного через hourCycle: 'h12' или hourCycle: 'h11'. В 24-часовом формате они не используются, так как номер часа даёт всю необходимую информацию.
В разных локалях используются разные обозначения периодов дня и границы между ними могут отличаться. Форматтер применяет эти правила автоматически на основе идентификатора локали. Например, британский английский считает 4:30 AM «ночью», а американский — «утром».