Как форматировать время в локали пользователя

Используйте JavaScript для отображения времени в соответствии с региональными стандартами каждого пользователя

Введение

Время отображается по-разному в разных частях мира. Американцы обычно видят 3:30 PM, отображаемое как 3:30 PM, в то время как большинство европейцев ожидают 15:30. Когда вы жестко задаете формат времени, вы предполагаете, что все пользователи следуют одной и той же конвенции.

Отображение времени в непривычном формате создает путаницу. Пользователь, привыкший к 24-часовому формату, видя 3:30 PM, должен мысленно преобразовать его, чтобы понять, идет ли речь о утре или вечере. Эта когнитивная нагрузка увеличивается с каждым временем в вашем приложении.

JavaScript предоставляет API Intl.DateTimeFormat для автоматической обработки форматирования времени. Этот урок объясняет, почему форматы времени различаются в разных культурах, как работает API и как правильно форматировать время для любого региона.

Почему форматы времени различаются в зависимости от региона

Разные регионы разработали разные конвенции для отображения времени. Эти конвенции отражают исторические практики, образовательные системы и культурные предпочтения. Универсального формата не существует.

В Соединенных Штатах, Канаде, Австралии и на Филиппинах используется 12-часовой формат с указателями AM и PM. 3:30 дня отображается как 3:30 PM.

В большинстве европейских стран, Латинской Америке и Азии используется 24-часовой формат без указателей AM и PM. То же самое время отображается как 15:30.

Символ-разделитель между часами и минутами также различается. В англоязычных странах используются двоеточия, в то время как в некоторых регионах используются точки или другие знаки препинания.

Способ отображения AM и PM также отличается. В английском языке используются AM и PM, в испанском — a.m. и p.m., а в некоторых регионах эти указатели размещаются перед временем, а не после.

Когда вы отображаете время, вам нужно соответствовать ожиданиям пользователя как по формату часов, так и по конкретным конвенциям форматирования.

Использование Intl.DateTimeFormat для форматирования времени

Intl.DateTimeFormat — это конструктор, который создаёт форматировщик, применяющий локаль-специфичные соглашения. Чтобы отформатировать время, передайте идентификатор локали в качестве первого аргумента и укажите параметры, связанные с временем, во втором аргументе.

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});

const date = new Date('2025-03-15T15:30:00');
console.log(formatter.format(date));
// Вывод: "3:30 PM"

Этот код создаёт форматировщик для английского языка (США), который отображает часы и минуты. Опции hour и minute указывают форматировщику включить эти компоненты. Метод format() преобразует объект Date в строку с соответствующим форматированием.

Конструктор Date принимает строку даты и времени в формате ISO 8601, например, 2025-03-15T15:30:00. Это создаёт объект Date, представляющий 15:30 15 марта 2025 года. Затем форматировщик преобразует это в строку времени, специфичную для локали.

Форматирование одного и того же времени для разных локалей

Вы можете форматировать одно и то же время для разных локалей, изменяя идентификатор локали, передаваемый в конструктор.

const date = new Date('2025-03-15T15:30:00');

const usFormatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(usFormatter.format(date));
// Вывод: "3:30 PM"

const gbFormatter = new Intl.DateTimeFormat('en-GB', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(gbFormatter.format(date));
// Вывод: "15:30"

const deFormatter = new Intl.DateTimeFormat('de-DE', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(deFormatter.format(date));
// Вывод: "15:30"

const frFormatter = new Intl.DateTimeFormat('fr-FR', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(frFormatter.format(date));
// Вывод: "15:30"

Каждый форматировщик применяет разные соглашения. Форматировщик для США использует 12-часовой формат с указанием AM/PM. Форматировщики для Великобритании, Германии и Франции используют 24-часовой формат без указания AM/PM.

Вам не нужно знать, какой формат используется в каждой локали. API автоматически обрабатывает эти детали на основе идентификатора локали.

Включение секунд в отображение времени

Вы можете добавить опцию second, чтобы отображать секунды вместе с часами и минутами.

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

const date = new Date('2025-03-15T15:30:45');
console.log(formatter.format(date));
// Вывод: "3:30:45 PM"

Опция second работает так же, как hour и minute. Установите её значение в 'numeric', чтобы включить секунды в вывод.

Управление добавлением нулей с помощью 2-digit

Опции hour, minute и second принимают два значения: 'numeric' и '2-digit'. Значение 'numeric' отображает цифры без добавления нулей, в то время как '2-digit' всегда отображает две цифры с ведущими нулями.

const date = new Date('2025-03-15T09:05:03');

const numericFormatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});
console.log(numericFormatter.format(date));
// Вывод: "9:05:03 AM"

const twoDigitFormatter = new Intl.DateTimeFormat('en-US', {
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit'
});
console.log(twoDigitFormatter.format(date));
// Вывод: "09:05:03 AM"

Форматер с 'numeric' отображает 9:05:03 AM с одной цифрой для часа. Форматер с '2-digit' отображает 09:05:03 AM с ведущим нулём для часа. Оба форматера отображают две цифры для минут и секунд, так как эти значения обычно дополняются нулями независимо от настройки.

Принудительное использование 12-часового или 24-часового формата

По умолчанию API использует формат времени, предпочтительный для локали. Вы можете переопределить это с помощью опции hour12.

const date = new Date('2025-03-15T15:30:00');

const hour12Formatter = new Intl.DateTimeFormat('en-GB', {
  hour: 'numeric',
  minute: 'numeric',
  hour12: true
});
console.log(hour12Formatter.format(date));
// Вывод: "3:30 pm"

const hour24Formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  hour12: false
});
console.log(hour24Formatter.format(date));
// Вывод: "15:30"

Установка hour12: true принудительно включает 12-часовой формат даже для локалей, которые обычно используют 24-часовой формат. Установка hour12: false принудительно включает 24-часовой формат даже для локалей, которые обычно используют 12-часовой формат.

Локаль всё равно определяет другие детали форматирования, такие как пунктуация и пробелы. Форматер для Великобритании с hour12: true отображает 3:30 pm с маленькими буквами pm, в то время как форматер для США отображает 3:30 PM с заглавными буквами PM.

Форматирование времени для локали пользователя

Вместо жесткого указания конкретной локали вы можете использовать предпочитаемый язык пользователя из браузера. Свойство navigator.language возвращает предпочтительный язык пользователя.

const userLocale = navigator.language;
const formatter = new Intl.DateTimeFormat(userLocale, {
  hour: 'numeric',
  minute: 'numeric'
});

const date = new Date('2025-03-15T15:30:00');
console.log(formatter.format(date));
// Вывод зависит от локали пользователя
// Для en-US: "3:30 PM"
// Для en-GB: "15:30"
// Для de-DE: "15:30"
// Для fr-FR: "15:30"

Этот подход отображает время в соответствии с ожиданиями каждого пользователя, не требуя от них ручного выбора локали. Браузер предоставляет предпочтительный язык, а API Intl применяет соответствующие правила форматирования.

Вы также можете передать весь массив предпочитаемых языков, чтобы включить поведение с резервным вариантом.

const formatter = new Intl.DateTimeFormat(navigator.languages, {
  hour: 'numeric',
  minute: 'numeric'
});

const date = new Date('2025-03-15T15:30:00');
console.log(formatter.format(date));

API использует первую поддерживаемую локаль из массива. Это обеспечивает лучшее поведение с резервным вариантом, если предпочтительная локаль пользователя недоступна.

Создание времени для форматирования

Вы можете создавать объекты Date с информацией о времени несколькими способами. Самый надежный способ — использовать строки даты и времени в формате ISO 8601.

const time1 = new Date('2025-03-15T09:00:00');
const time2 = new Date('2025-03-15T15:30:00');
const time3 = new Date('2025-03-15T23:45:30');

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});

console.log(formatter.format(time1));
// Вывод: "9:00 AM"

console.log(formatter.format(time2));
// Вывод: "3:30 PM"

console.log(formatter.format(time3));
// Вывод: "11:45 PM"

Строки даты и времени в формате ISO 8601 используют формат YYYY-MM-DDTHH:MM:SS. Символ T разделяет дату и время. Этот формат однозначен и работает последовательно во всех локалях и часовых поясах.

Форматирование времени из временных меток

Вы также можете создавать объекты Date из временных меток Unix. Временная метка Unix представляет собой количество миллисекунд, прошедших с 1 января 1970 года по UTC.

const timestamp = 1710515400000; // 15 марта 2025 года в 15:30
const date = new Date(timestamp);

const formatter = new Intl.DateTimeFormat('ru-RU', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(formatter.format(date));
// Вывод: "15:30"

Этот подход работает, когда вы получаете временные метки из API, баз данных или других систем, представляющих время в виде чисел.

Вы также можете передать временную метку напрямую в метод format() без создания объекта Date.

const formatter = new Intl.DateTimeFormat('ru-RU', {
  hour: 'numeric',
  minute: 'numeric'
});

const timestamp = 1710515400000;
console.log(formatter.format(timestamp));
// Вывод: "15:30"

API принимает как объекты Date, так и временные метки. Используйте тот подход, который лучше подходит для вашего кода.

Форматирование текущего времени

Чтобы отформатировать текущее время, создайте объект Date без аргументов. Это создаст объект Date, представляющий текущий момент.

const formatter = new Intl.DateTimeFormat('ru-RU', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

const now = new Date();
console.log(formatter.format(now));
// Вывод: "15:45:12" (или текущее время при выполнении)

Вы также можете напрямую передать Date.now(), который возвращает текущую временную метку в виде числа.

const formatter = new Intl.DateTimeFormat('ru-RU', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

console.log(formatter.format(Date.now()));
// Вывод: "15:45:12" (или текущее время при выполнении)

Оба подхода дают идентичные результаты.

Повторное использование форматтеров для повышения производительности

Создание нового экземпляра Intl.DateTimeFormat включает загрузку данных локали и обработку параметров. Если вам нужно форматировать несколько временных значений с одной и той же локалью и настройками, создайте форматтер один раз и используйте его повторно.

const formatter = new Intl.DateTimeFormat('ru-RU', {
  hour: 'numeric',
  minute: 'numeric'
});

const times = [
  new Date('2025-03-15T09:00:00'),
  new Date('2025-03-15T12:30:00'),
  new Date('2025-03-15T18:45:00')
];

times.forEach(time => {
  console.log(formatter.format(time));
});
// Вывод:
// "9:00"
// "12:30"
// "18:45"

Этот подход более эффективен, чем создание нового форматтера для каждого времени. Разница в производительности становится значительной при форматировании массивов с сотнями или тысячами временных значений.

Форматирование времени в шаблонах

Вы можете использовать Intl.DateTimeFormat везде, где отображаете время для пользователей. Это включает вставку отформатированного времени в HTML-шаблоны, отображение времени в таблицах или показ временных меток в пользовательских интерфейсах.

const formatter = new Intl.DateTimeFormat(navigator.language, {
  hour: 'numeric',
  minute: 'numeric'
});

const eventStart = new Date('2025-03-15T14:00:00');
const eventEnd = new Date('2025-03-15T16:30:00');

document.getElementById('start-time').textContent = formatter.format(eventStart);
document.getElementById('end-time').textContent = formatter.format(eventEnd);

Отформатированные строки работают как любые другие строковые значения. Вы можете вставлять их в текстовый контент, атрибуты или любой другой контекст, где отображаете информацию для пользователей.