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

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

В Luxon временная метка представляется через объект DateTime, который содержит не только сам момент времени, но и контекст: часовую зону, локаль и дополнительные параметры интерпретации. Это отличает его от нативного Date, который хранит только абсолютное значение времени в миллисекундах.


Представление временной метки как неизменяемого значения

Ключевая особенность модели Luxon — иммутабельность. Любая операция над DateTime возвращает новый объект, а не изменяет существующий. Это упрощает сохранение состояния временных меток, так как исключаются побочные эффекты.

import { DateTime } from "luxon";

const dt = DateTime.local(2026, 5, 23, 10, 30);
const updated = dt.plus({ hours: 2 });

В данном случае dt остаётся неизменным, а updated представляет новую временную метку.


Основные способы сериализации

Для сохранения временной метки необходимо преобразовать объект DateTime в формат, пригодный для хранения. Luxon предоставляет несколько стандартных методов.

ISO-формат

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

const dt = DateTime.utc(2026, 5, 23, 12, 0);

const isoString = dt.toISO();

Результат будет выглядеть как строка:

2026-05-23T12:00:00.000Z

Преимущество ISO-формата заключается в том, что он однозначно интерпретируется в любой системе, поддерживающей стандарт.


UNIX timestamp (миллисекунды)

Для компактного хранения и быстрого сравнения часто используется числовое представление времени — количество миллисекунд с начала эпохи Unix.

const dt = DateTime.local();

const timestamp = dt.toMillis();

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


Секундный timestamp

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

const seconds = Math.floor(dt.toSeconds());

Этот формат занимает меньше памяти, но теряет точность до миллисекунд.


Восстановление временных меток

Сохранённые значения должны быть корректно восстановлены в объект DateTime.

Восстановление из ISO

const restored = DateTime.fromISO("2026-05-23T12:00:00.000Z");

Luxon автоматически интерпретирует временную зону, если она присутствует в строке.


Восстановление из timestamp

const restored = DateTime.fromMillis(1716465600000);

Такой способ является наиболее быстрым, так как не требует парсинга строки.


Сохранение временной зоны

Одной из ключевых проблем при хранении времени является потеря информации о временной зоне. Luxon решает это через явное указание зоны при создании или сериализации.

const dt = DateTime.now().setZone("Europe/Paris");
const saved = dt.toISO();

При восстановлении важно учитывать, что строка ISO может содержать смещение:

const restored = DateTime.fromISO(saved, { setZone: true });

Параметр setZone: true сохраняет оригинальную временную зону вместо преобразования в локальную.


Хранение в JSON

При сериализации объектов в JSON временные метки требуют явного преобразования, так как DateTime не сериализуется автоматически.

const event = {
  name: "Meeting",
  time: DateTime.local().toISO()
};

const json = JSON.stringify(event);

При восстановлении:

const parsed = JSON.parse(json);
const time = DateTime.fromISO(parsed.time);

Такой подход предотвращает потерю структуры данных.


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

При работе с реляционными базами данных чаще всего используются два подхода:

  1. ISO-строки — для читаемости и совместимости с SQL-функциями.
  2. timestamp (BIGINT) — для производительности и индексации.

Пример хранения ISO:

INS ERT INTO events (name, time)
VALUES ('Meeting', '2026-05-23T12:00:00.000Z');

Пример хранения timestamp:

INS ERT IN TO events (name, time)
VALUES ('Meeting', 1716465600000);

Luxon одинаково эффективно восстанавливает оба формата.


Потеря контекста и её предотвращение

При сохранении временных меток важно учитывать, что часть информации может быть утрачена:

  • локаль (locale)
  • форматирование
  • временная зона (если не сохранена явно)

Luxon разделяет «момент времени» и «представление». Сохранению подлежит именно момент, а не формат отображения.

const dt = DateTime.local().setLocale("ru").setZone("Europe/Moscow");

const saved = {
  val ue: dt.toISO(),
  zone: dt.zoneName
};

Восстановление:

const restored = DateTime.fromISO(saved.value, { zone: saved.zone });

Работа с серверным и клиентским временем

При распределённых системах важно различать источник времени. Серверное время считается эталонным, клиентское — потенциально изменяемым.

Сохранение временных меток на сервере обычно выполняется в UTC:

const serverTime = DateTime.utc().toISO();

На клиенте оно интерпретируется с учётом локальной зоны:

const localTime = DateTime.fromISO(serverTime).toLocal();

Стабильность хранения и сравнение значений

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

const a = DateTime.fromISO("2026-05-23T10:00:00Z");
const b = DateTime.fromISO("2026-05-23T11:00:00Z");

const result = a.toMillis() < b.toMillis();

Сравнение объектов напрямую невозможно из-за их иммутабельной структуры.


Поток данных и сериализация в реальном времени

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

const event = {
  type: "update",
  timestamp: DateTime.utc().toMillis()
};

На стороне получателя:

const received = DateTime.fromMillis(event.timestamp);

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


Частые ошибки при сохранении временных меток

  • сохранение локального времени без указания зоны
  • смешивание ISO и timestamp в одной системе
  • повторное преобразование DateTime через Date
  • потеря миллисекунд при округлении до секунд без необходимости
  • игнорирование setZone(true) при восстановлении

Корректная модель хранения всегда опирается на один источник истины: либо UTC ISO, либо epoch timestamp, без смешивания представлений.