Сериализация для отправки

Библиотека Luxon работает с датами и временем через объект DateTime, который не является примитивом JavaScript и не может быть напрямую передан через сетевые протоколы без преобразования. При попытке отправки таких объектов через HTTP, WebSocket или сохранении в JSON происходит потеря структуры, если не выполнить явную сериализацию.

Базовая проблема сериализации DateTime

Любой объект DateTime содержит внутреннее состояние: дату, время, таймзону, локаль, календарные настройки. Однако стандартный JSON не поддерживает сложные типы.

import { DateTime } from "luxon";

const dt = DateTime.now();

JSON.stringify({ time: dt });

Результат:

{"time":{}}

Объект теряет данные, поскольку JSON.stringify не знает, как преобразовать DateTime.


Встроенный механизм toJSON

Luxon решает проблему через метод toJSON(), встроенный в DateTime. При наличии этого метода JSON автоматически использует его при сериализации.

const dt = DateTime.now();

JSON.stringify({ time: dt });

Результат:

{"time":"2026-05-23T14:30:00.000+03:00"}

Формат — ISO 8601, расширенный с учётом таймзоны.

Особенности поведения toJSON

  • Используется автоматически JSON.stringify
  • Возвращает строку ISO
  • Сохраняет смещение часового пояса
  • Подходит для межсистемного обмена

Явные методы сериализации Luxon

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

ISO-строка (основной формат)

dt.toISO();

Пример результата:

2026-05-23T14:30:00.000+03:00

Используется в API, логах и межсервисной коммуникации.


Упрощённый JSON-формат

dt.toJSON();

Фактически эквивалентен toISO().


Формат HTTP-даты

dt.toHTTP();

Пример:

Sat, 23 May 2026 11:30:00 GMT

Используется в заголовках HTTP (Expires, Last-Modified).


Кастомная сериализация через format

dt.toFormat("yyyy-MM-dd HH:mm:ss");

Пример:

2026-05-23 14:30:00

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


Сериализация в UNIX timestamp

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

Миллисекунды

dt.toMillis();

Результат:

1716466200000

Секунды

Math.floor(dt.toSeconds());

Применяется в UNIX API и некоторых базах данных.


Обратная десериализация

Переданные значения необходимо восстановить обратно в DateTime.

Из ISO строки

DateTime.fromISO("2026-05-23T14:30:00.000+03:00");

Из миллисекунд

DateTime.fromMillis(1716466200000);

Из объекта JavaScript Date

DateTime.fromJSDate(new Date());

Полный цикл сериализации и восстановления

import { DateTime } from "luxon";

const original = DateTime.now();

// сериализация
const payload = JSON.stringify({
  createdAt: original
});

// десериализация
const parsed = JSON.parse(payload, (key, value) => {
  if (key === "createdAt") {
    return DateTime.fromISO(value);
  }
  return value;
});

Работа с API и REST-интерфейсами

При передаче данных на сервер чаще всего используется ISO 8601.

const event = {
  title: "Meeting",
  start: DateTime.now().plus({ hours: 2 }).toISO(),
};

fetch("/api/events", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify(event)
});

На сервере:

const start = DateTime.fromISO(req.body.start);

Таймзоны и их влияние на сериализацию

Luxon строго учитывает таймзону при сериализации.

DateTime.now().setZone("Europe/Paris").toISO();

Результат:

2026-05-23T13:30:00.000+02:00

При смене зоны меняется и строка, что критично для распределённых систем.


UTC как универсальный формат обмена

Для устранения неоднозначности часто используется UTC.

DateTime.now().toUTC().toISO();

Результат:

2026-05-23T11:30:00.000Z

Суффикс Z означает нулевое смещение.


Пользовательская JSON-сериализация через replacer

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

function replacer(key, value) {
  if (value && value.isLuxonDateTime) {
    return {
      __type: "DateTime",
      value: value.toISO()
    };
  }
  return value;
}

Использование:

JSON.stringify(data, replacer);

Восстановление через reviver

function reviver(key, value) {
  if (value && value.__type === "DateTime") {
    return DateTime.fromISO(value.value);
  }
  return value;
}
JSON.parse(json, reviver);

Потенциальные ошибки при сериализации

Потеря таймзоны

Использование toFormat без зоны:

dt.toFormat("yyyy-MM-dd HH:mm");

Не содержит информации о смещении, что может привести к ошибкам интерпретации.


Нестабильность локального времени

DateTime.local().toISO();

Зависит от среды выполнения (сервер/браузер), что усложняет воспроизводимость.


Неправильное хранение DateTime как объекта

const obj = { time: DateTime.now() };

Без сериализации в строку приводит к пустым объектам в JSON.


Оптимизация передачи данных

Для высоконагруженных систем выбирается один стандарт:

  • ISO 8601 для API
  • UNIX timestamp для аналитики
  • HTTP-date для заголовков
  • кастомный формат для legacy-систем

Сравнение форматов сериализации

Метод Тип Содержит таймзону Читаемость Совместимость
toISO строка да высокая высокая
toJSON строка да высокая высокая
toMillis число нет низкая очень высокая
toFormat строка зависит средняя средняя
toHTTP строка GMT средняя HTTP-специфичная

Поведение JSON.stringify с DateTime

Luxon специально реализует toJSON, что делает объект совместимым с JSON без дополнительных преобразований.

const payload = JSON.stringify({
  now: DateTime.now()
});

Эквивалентно:

JSON.stringify({
  now: DateTime.now().toISO()
});

Использование в распределённых системах

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

Часто используется схема:

{
  createdAt: DateTime.utc().toISO(),
  updatedAt: DateTime.utc().toISO()
}

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


Хранение в базах данных

При работе с SQL и NoSQL:

  • PostgreSQL: timestamp with time zone + ISO
  • MongoDB: ISODate (совместим с ISO 8601)
  • Redis: UNIX timestamp или ISO строка

Пример подготовки данных:

const record = {
  created_at: DateTime.utc().toISO(),
  expires_at: DateTime.utc().plus({ days: 7 }).toISO()
};

Детерминированная сериализация

Для тестирования важно получать одинаковый результат:

DateTime.fromObject({
  year: 2026,
  month: 5,
  day: 23,
  zone: "UTC"
}).toISO();

Это исключает влияние локального окружения и системного времени.