Форматы дат по странам

Региональные различия представления дат

Ввод даты в веб-интерфейсах требует учёта локальных стандартов, поскольку порядок компонентов даты существенно различается в разных странах. Библиотека Inputmask в JavaScript предоставляет механизмы для унифицированного контроля ввода, но корректная настройка масок даты опирается на понимание региональных форматов.

Наиболее распространённые варианты представления даты:

  • dd/mm/yyyy — день, месяц, год
  • mm/dd/yyyy — месяц, день, год
  • yyyy-mm-dd — год, месяц, день (ISO 8601)

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

Европейская модель: dd/mm/yyyy

Формат dd/mm/yyyy широко используется в большинстве стран Европы, Латинской Америки, а также в ряде азиатских регионов. В Inputmask он обычно задаётся через шаблон:

Inputmask("99/99/9999").mask(input);

В данном случае:

  • 99 — числовой символ дня
  • 99 — числовой символ месяца
  • 9999 — четырёхзначный год

Ключевая особенность данного формата — интуитивная привязка к календарной логике: сначала уточняется день, затем месяц, затем год. Однако при программной обработке это создаёт неоднозначность, поскольку числовые значения 01–12 могут интерпретироваться только как месяц, но не как день.

Для повышения точности часто добавляются ограничения через definitions или prevalidator:

Inputmask({
  mask: "39/19/9999",
  definitions: {
    "3": {
      validator: "[0-3]",
      cardinality: 1
    },
    "1": {
      validator: "[0-1]",
      cardinality: 1
    }
  }
}).mask(input);

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

Североамериканский формат: mm/dd/yyyy

В США и частично в Канаде используется формат mm/dd/yyyy, где месяц предшествует дню. Это исторически связано с делопроизводственными традициями и стало стандартом де-факто.

В Inputmask конфигурация маски аналогична:

Inputmask("99/99/9999").mask(input);

Однако логическая интерпретация полей меняется: первое поле теперь соответствует месяцу.

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

Inputmask("datetime", {
  inputFormat: "mm/dd/yyyy",
  placeholder: "mm/dd/yyyy"
}).mask(input);

Использование встроенного alias datetime позволяет библиотеке учитывать контекст формата и корректно обрабатывать ввод.

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

Международный стандарт: yyyy-mm-dd (ISO 8601)

Формат ISO 8601 является наиболее универсальным и используется в программировании, базах данных и API-интерфейсах. Его ключевое преимущество — однозначность сортировки и интерпретации.

В Inputmask он задаётся следующим образом:

Inputmask("9999-99-99").mask(input);

Или через alias:

Inputmask("datetime", {
  inputFormat: "yyyy-mm-dd"
}).mask(input);

Преимущества данного формата:

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

При работе с ISO-форматом часто используется строгая валидация диапазонов:

Inputmask({
  mask: "9999-99-99",
  placeholder: "yyyy-mm-dd",
  leapday: "29.02.",
  yearrange: { minyear: 1900, maxyear: 2099 }
}).mask(input);

Азиатские форматы и вариации порядка

В некоторых странах Восточной Азии используется формат yyyy年mm月dd日, где элементы даты сопровождаются текстовыми символами. Inputmask поддерживает такие конструкции через комбинированные маски:

Inputmask("9999年99月99日").mask(input);

Здесь важно учитывать:

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

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

Гибкие маски и адаптация под локаль

Inputmask позволяет создавать динамические маски, зависящие от локали пользователя. Это достигается через условную инициализацию:

const locale = navigator.language;

if (locale === "en-US") {
  Inputmask("99/99/9999").mask(input);
} else if (locale === "en-GB") {
  Inputmask("99/99/9999").mask(input);
} else {
  Inputmask("9999-99-99").mask(input);
}

Более сложные реализации используют централизованные конфигурации:

const dateMasks = {
  "en-US": "99/99/9999",
  "en-GB": "99/99/9999",
  "de-DE": "99.99.9999",
  "iso": "9999-99-99"
};

Inputmask(dateMasks[locale] || dateMasks.iso).mask(input);

Разделители и региональные символы

Помимо порядка элементов, существенное значение имеют разделители:

  • / — США, Япония (в упрощённых интерфейсах)
  • . — Германия, Россия, Центральная Европа
  • - — ISO и цифровые системы
  • 年/月/日 — Восточная Азия

Inputmask допускает комбинирование любых символов:

Inputmask("99.99.9999").mask(input);
Inputmask("99-99-9999").mask(input);

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

Валидация календарных ограничений

Маска сама по себе не гарантирует корректность даты. Например, значение 39/19/2025 формально может соответствовать шаблону, но не является реальной датой.

Для решения этой задачи применяются дополнительные валидаторы:

Inputmask({
  alias: "datetime",
  inputFormat: "dd/mm/yyyy",
  isComplete: function(buffer) {
    const day = parseInt(buffer[0] + buffer[1], 10);
    const month = parseInt(buffer[3] + buffer[4], 10);
    return month >= 1 && month <= 12 && day >= 1 && day <= 31;
  }
}).mask(input);

Более строгая проверка учитывает количество дней в месяце и високосные годы.

Работа с алиасом datetime

Alias datetime в Inputmask представляет собой специализированный режим, который упрощает настройку сложных масок дат:

Inputmask("datetime", {
  inputFormat: "dd/mm/yyyy",
  placeholder: "dd/mm/yyyy",
  separator: "/"
}).mask(input);

Внутри alias реализуется:

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

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

Конфликты локалей и преобразование данных

При хранении дат в системах с несколькими локалями возникает проблема конвертации форматов. Inputmask решает задачу только на уровне ввода, поэтому преобразование выполняется отдельно:

function toISO(date) {
  const parts = date.split("/");
  return `${parts[2]}-${parts[1]}-${parts[0]}`;
}

Такая нормализация необходима при отправке данных на сервер, где обычно используется ISO 8601 независимо от пользовательского региона.

Особенности поведения курсора и UX

Разные форматы даты влияют на поведение курсора при вводе:

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

Inputmask автоматически управляет позиционированием курсора, но при сложных масках с нестандартными символами может потребоваться ручная настройка positionCaretOnClick.

Маски с переменной длиной года

Некоторые системы используют двухзначный год (yy) вместо четырёхзначного. В Inputmask это задаётся упрощённой маской:

Inputmask("99/99/99").mask(input);

Однако такая форма создаёт неоднозначность интерпретации века, что требует дополнительной логики преобразования:

function normalizeYear(yy) {
  return parseInt(yy, 10) < 50 ? `20${yy}` : `19${yy}`;
}

Смешанные форматы и миграционные сценарии

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

Типовой подход:

  • ввод в локальном формате;
  • немедленная нормализация;
  • хранение в ISO 8601;
  • отображение в зависимости от локали интерфейса.

Такой подход снижает риск ошибок при международной интеграции и обеспечивает предсказуемость обработки временных данных.