Эры и календарные периоды

Библиотека Globalize использует данные стандарта CLDR для корректного отображения календарей, эпох, названий периодов времени и локализованных обозначений дат. Поддержка эр особенно важна при работе с историческими датами, японским календарём, буддийским летоисчислением и другими системами, отличающимися от григорианского календаря.

Globalize не хранит календарные данные самостоятельно. Все сведения об эрах, форматах дат и периодах времени поступают из CLDR через библиотеку Cldr.js.

Подключение модулей

Для работы с датами и календарями подключаются основные зависимости:

const Globalize = require("globalize");

require("cldr-data").entireSupplemental();
require("cldr-data").entireMainFor("ru", "en", "ja");

Globalize.load(
  require("cldr-data/supplemental/likelySubtags.json"),
  require("cldr-data/supplemental/timeData.json"),
  require("cldr-data/supplemental/weekData.json"),
  require("cldr-data/main/ru/ca-gregorian.json"),
  require("cldr-data/main/en/ca-gregorian.json"),
  require("cldr-data/main/ja/ca-japanese.json")
);

После загрузки данных создаётся объект локализации:

const ru = new Globalize("ru");
const en = new Globalize("en");
const ja = new Globalize("ja");

Понятие эры в CLDR и Globalize

Эра — это исторический или календарный период, используемый для отсчёта лет.

Примеры:

  • до нашей эры / нашей эры;
  • BC / AD;
  • японские эпохи Reiwa, Heisei, Showa;
  • буддийская эра.

CLDR хранит:

  • краткие обозначения;
  • полные названия;
  • узкие формы записи;
  • правила отображения;
  • локализованные варианты.

Globalize использует эти данные автоматически при форматировании даты.


Форматирование эр

Для отображения эпох применяются специальные символы шаблона даты.

Символ G

Символ G отвечает за отображение эры.

Количество символов определяет стиль вывода.

Формат Результат
G н.э.
GG н.э.
GGG н.э.
GGGG нашей эры
GGGGG н

Пример форматирования

const formatter = ru.dateFormatter({
  datetime: "medium",
  raw: "d MMMM y G"
});

console.log(formatter(new Date()));

Результат:

5 марта 2026 н.э.

Полное название эры

const formatter = ru.dateFormatter({
  raw: "d MMMM y GGGG"
});

console.log(formatter(new Date()));

Результат:

5 марта 2026 нашей эры

Узкий формат эры

const formatter = ru.dateFormatter({
  raw: "d.MM.y GGGGG"
});

console.log(formatter(new Date()));

Результат:

05.03.2026 н

Эры в английской локали

const formatter = en.dateFormatter({
  raw: "MMMM d, y G"
});

console.log(formatter(new Date()));

Результат:

March 5, 2026 AD

Полная форма:

const formatter = en.dateFormatter({
  raw: "MMMM d, y GGGG"
});

Результат:

March 5, 2026 Anno Domini

Даты до нашей эры

Javascript использует астрономическое представление годов.

Год 0 соответствует 1 BC.

Пример:

const ancientDate = new Date(-44, 2, 15);

const formatter = en.dateFormatter({
  raw: "d MMM y G"
});

console.log(formatter(ancientDate));

Результат:

15 Mar 45 BC

Следует учитывать особенности объекта Date:

  • отрицательные годы работают нестабильно в старых движках;
  • часовые пояса могут влиять на отображение;
  • некоторые браузеры ограничивают диапазон исторических дат.

Японские эры

Одной из наиболее интересных возможностей CLDR является поддержка японского императорского календаря.

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

Примеры эпох:

Эра Начало
Meiji 1868
Taisho 1912
Showa 1926
Heisei 1989
Reiwa 2019

Подключение японского календаря

Globalize.load(
  require("cldr-data/main/ja/ca-japanese.json")
);

const ja = new Globalize("ja");

Форматирование японской эры

const formatter = ja.dateFormatter({
  date: "long",
  skeleton: "GyMMMd"
});

console.log(formatter(new Date(2020, 4, 1)));

Результат:

令和2年5月1日

Здесь:

  • 令和 — эпоха Reiwa;
  • 2年 — второй год эпохи.

Использование шаблона с эрой

const formatter = ja.dateFormatter({
  raw: "GGGG y年M月d日"
});

Результат:

令和 2年5月1日

Краткие и полные обозначения

CLDR хранит несколько вариантов отображения эр:

Abbreviated

Сокращённый вариант.

AD
BC

Wide

Полное название.

Anno Domini
Before Christ

Narrow

Минимальная форма.

A
B

Globalize выбирает нужную форму автоматически по длине шаблона G.


Календарные периоды

Globalize поддерживает локализованные периоды времени:

  • AM / PM;
  • полдень;
  • полночь;
  • утро;
  • вечер;
  • ночь.

Эти данные также поступают из CLDR.


Форматирование AM и PM

const formatter = ru.dateFormatter({
  raw: "h:mm a"
});

console.log(formatter(new Date(2026, 2, 5, 9, 30)));

Результат:

9:30 AM

Для русского языка стандартные обозначения могут отличаться в зависимости от версии CLDR.


Локализация периодов времени

const formatter = en.dateFormatter({
  raw: "h:mm a"
});

console.log(formatter(new Date(2026, 2, 5, 21, 15)));

Результат:

9:15 PM

Широкие календарные периоды

CLDR содержит расширенные периоды суток:

Период Пример
morning утро
afternoon день
evening вечер
night ночь

Некоторые локали используют их автоматически.


Символ B

Современный формат Unicode поддерживает символ B для расширенных периодов суток.

const formatter = en.dateFormatter({
  raw: "h B"
});

Возможные результаты:

9 at night
11 in the morning
3 in the afternoon

Использование в русской локали

const formatter = ru.dateFormatter({
  raw: "H B"
});

Результат может выглядеть так:

22 ночью

Поддержка зависит от версии CLDR и реализации Intl в окружении.


Полночь и полдень

Некоторые локали различают:

  • midnight;
  • noon.

Пример:

const formatter = en.dateFormatter({
  raw: "h:mm B"
});

console.log(formatter(new Date(2026, 2, 5, 0, 0)));
console.log(formatter(new Date(2026, 2, 5, 12, 0)));

Результат:

12:00 midnight
12:00 noon

Использование skeleton-форматов

Skeleton позволяет Globalize самостоятельно подобрать локализованный шаблон.

Пример:

const formatter = ru.dateFormatter({
  skeleton: "GyMMMd"
});

Здесь:

  • G — эра;
  • y — год;
  • MMM — месяц;
  • d — день.

Отличие raw от skeleton

raw

Точный шаблон.

raw: "d MMMM y G"

Полный контроль над выводом.


skeleton

Гибкий локализованный формат.

skeleton: "GyMMMd"

Globalize сам определяет:

  • порядок элементов;
  • разделители;
  • стиль записи.

Получение данных CLDR напрямую

Иногда требуется получить сведения об эпохах вручную.

Пример через Cldr.js:

const Cldr = require("cldrjs");

const cldr = new Cldr("en");

const eras = cldr.main("dates/calendars/gregorian/eras");
console.log(eras);

Результат содержит:

{
  eraNames: {
    0: "Before Christ",
    1: "Anno Domini"
  }
}

Эры в разных календарях

CLDR поддерживает множество календарных систем:

Календарь Особенности
gregorian стандартный григорианский
japanese японские эпохи
buddhist буддийское летоисчисление
islamic исламский календарь
roc календарь Китайской Республики
persian персидский календарь

Буддийская эра

В буддийском календаре годы смещены относительно григорианского.

Пример:

Globalize.load(
  require("cldr-data/main/th/ca-buddhist.json")
);

const th = new Globalize("th");

Форматирование:

const formatter = th.dateFormatter({
  raw: "d MMMM y G"
});

Результат:

5 มีนาคม 2569 พ.ศ.

Настройка календаря

Некоторые локали позволяют явно выбирать календарь через Unicode Extension.

Пример:

const jaJapanese = new Globalize("ja-u-ca-japanese");

Теперь форматирование использует японский календарь автоматически.


Unicode Calendar Extension

Расширение u-ca определяет календарную систему.

Примеры:

Значение Календарь
u-ca-gregory григорианский
u-ca-japanese японский
u-ca-buddhist буддийский
u-ca-islamic исламский

Практический пример локализации

function createFormatter(locale) {
  const globalize = new Globalize(locale);

  return globalize.dateFormatter({
    skeleton: "GyMMMd"
  });
}

const formatRu = createFormatter("ru");
const formatJa = createFormatter("ja-u-ca-japanese");

console.log(formatRu(new Date()));
console.log(formatJa(new Date()));

Возможный результат:

5 мар. 2026 г. н.э.
令和8年3月5日

Особенности работы с Intl

Globalize активно использует возможности Intl.DateTimeFormat.

Поддержка эр зависит от:

  • браузера;
  • версии Node.js;
  • ICU-данных;
  • версии CLDR.

Старые окружения могут:

  • не поддерживать символ B;
  • некорректно отображать исторические эпохи;
  • не иметь японского календаря.

Проверка поддержки календаря

console.log(
  Intl.DateTimeFormat.supportedLocalesOf([
    "ja-u-ca-japanese"
  ])
);

Если массив пуст, календарь не поддерживается.


Типичные ошибки

Не загружены данные календаря

Ошибка:

E_MISSING_CLDR

Причина:

require("cldr-data/main/ja/ca-japanese.json")

не был подключён.


Неверный skeleton

skeleton: "GGGG"

Skeleton не предназначен для точного форматирования эпох.

Для таких случаев лучше использовать raw.


Отсутствие ICU

В некоторых сборках Node.js доступны только английские данные.

Проверка:

console.log(Intl.DateTimeFormat().resolvedOptions());

Оптимизация загрузки CLDR

Полный набор данных CLDR может занимать значительный объём.

Часто загружают только необходимые календари:

Globalize.load(
  require("cldr-data/main/ru/ca-gregorian.json"),
  require("cldr-data/main/ja/ca-japanese.json")
);

Это уменьшает размер приложения.


Комбинирование эр и времени

const formatter = en.dateFormatter({
  raw: "EEEE, MMMM d, y G 'at' h:mm:ss a"
});

console.log(formatter(new Date()));

Результат:

Thursday, March 5, 2026 AD at 9:41:12 PM

Форматирование исторических дат

const formatter = en.dateFormatter({
  raw: "y G"
});

console.log(formatter(new Date(-500, 0, 1)));

Результат:

501 BC

Создание универсального форматтера

function createEraFormatter(locale, pattern) {
  const globalize = new Globalize(locale);

  return globalize.dateFormatter({
    raw: pattern
  });
}

const formatter = createEraFormatter(
  "en",
  "d MMM y GGGG"
);

console.log(formatter(new Date()));

Использование разных локалей

const locales = [
  "en",
  "ru",
  "ja-u-ca-japanese"
];

locales.forEach(locale => {
  const formatter = new Globalize(locale)
    .dateFormatter({
      skeleton: "GyMMMd"
    });

  console.log(locale, formatter(new Date()));
});

Возможный вывод:

en Mar 5, 2026 AD
ru 5 мар. 2026 г. н.э.
ja-u-ca-japanese 令和8年3月5日