Метод toSQL

Метод toSQL в библиотеке Luxon предназначен для преобразования объектов даты и времени в строку формата, совместимого с SQL-базами данных. Это один из ключевых инструментов при работе с серверными приложениями, где требуется передавать даты в SQL-запросах, сохранять их в базе или синхронизировать между сервисами.

В основе метода лежит идея унифицированного представления даты и времени, которое соответствует стандартному формату ISO, но адаптировано под особенности SQL-синтаксиса и поведения различных СУБД.

В большинстве реляционных баз данных даты и времена хранятся в специализированных типах:

  • DATE — только дата
  • TIME — только время
  • DATETIME / TIMESTAMP — дата и время вместе

Luxon предоставляет единый объект DateTime, а метод toSQL позволяет привести его к строке, которая может быть напрямую использована в SQL-запросах.

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

Базовое использование метода toSQL

Метод вызывается непосредственно на экземпляре DateTime:

import { DateTime } fr om "luxon";

const dt = DateTime.local(2026, 5, 23, 14, 30);

const sql = dt.toSQL();
console.log(sql);

Результат:

2026-05-23 14:30:00.000

По умолчанию Luxon возвращает:

  • дату в формате YYYY-MM-DD
  • время в формате HH:mm:ss.SSS
  • разделитель пробел между датой и временем
  • миллисекунды, даже если они равны 000

Сигнатура метода

Метод имеет следующую общую форму:

toSQL(options?: {
  includeOffset?: boolean,
  includeZone?: boolean,
  format?: string
})

Хотя фактическая реализация зависит от версии Luxon, ключевые параметры сохраняют стабильную семантику.

Управление временной зоной

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

includeOffset

Если включить includeOffset, строка будет содержать смещение относительно UTC:

const dt = DateTime.local(2026, 5, 23, 14, 30);

console.log(dt.toSQL({ includeOffset: true }));

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

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

Это особенно важно для систем, где:

  • данные сохраняются в UTC
  • но отображаются в локальном времени
  • требуется восстановление исходного контекста времени

Работа с временной зоной UTC

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

const dt = DateTime.utc(2026, 5, 23, 14, 30);

console.log(dt.toSQL({ includeZone: true }));

Результат:

2026-05-23 14:30:00.000 UTC

Параметр includeZone добавляет текстовое обозначение зоны, что полезно для логирования и аудита, но не всегда поддерживается SQL-движками напрямую.

Форматирование без времени

Если объект содержит только дату, Luxon автоматически адаптирует вывод:

const dt = DateTime.local(2026, 5, 23);

console.log(dt.toSQLDate());

Результат:

2026-05-23

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

Форматирование только времени

Аналогично можно получить только время:

const dt = DateTime.local(2026, 5, 23, 14, 30, 15);

console.log(dt.toSQLTime());

Результат:

14:30:15.000

Особенности поведения при неполных данных

Luxon строго нормализует дату и время. Если какие-то компоненты отсутствуют, они автоматически заполняются:

  • дата всегда полная (год, месяц, день)
  • время дополняется до 00:00:00.000

Пример:

const dt = DateTime.local(2026, 5);

console.log(dt.toSQL());

Результат:

2026-05-01 00:00:00.000

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

Сравнение с toISO

Методы toSQL и toISO часто используются вместе, но имеют разные цели:

  • toISO() → строгий стандарт ISO 8601
  • toSQL() → формат, удобный для баз данных

Различие:

const dt = DateTime.local(2026, 5, 23, 14, 30);

dt.toISO();
// 2026-05-23T14:30:00.000+03:00

dt.toSQL();
// 2026-05-23 14:30:00.000

SQL-формат более “читаемый” для человека и чаще используется в запросах INSERT и UPDATE.

Использование в SQL-запросах

Метод активно применяется при формировании строк запросов:

const dt = DateTime.local();

const query = `
  INS ERT IN TO users (created_at)
  VALUES ('${dt.toSQL()}')
`;

Результат вставки:

INS ERT IN TO users (created_at)
VALUES ('2026-05-23 14:30:00.000')

При этом важно учитывать необходимость параметризованных запросов, чтобы избежать SQL-инъекций.

Особенности работы с миллисекундами

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

const dt = DateTime.local(2026, 5, 23, 14, 30, 15);

console.log(dt.toSQL());

Результат:

2026-05-23 14:30:15.000

Это важно для систем, где требуется точная синхронизация событий, например:

  • логирование
  • финансовые транзакции
  • распределённые системы

Поведение при invalid DateTime

Если объект DateTime некорректен:

const dt = DateTime.invalid("error");

console.log(dt.toSQL());

Результат:

null

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

dt.isValid

Использование в ORM и дата-слое

Метод toSQL часто используется в связке с ORM и query builder’ами:

  • Knex
  • Sequelize (через кастомные преобразования)
  • TypeORM (в ручных SQL-выражениях)

Пример:

db("orders").insert({
  created_at: DateTime.utc().toSQL()
});

Такой подход обеспечивает совместимость с большинством SQL-диалектов.

Различия поведения в разных СУБД

Хотя формат универсален, некоторые базы данных интерпретируют строку по-разному:

  • PostgreSQL: полностью поддерживает YYYY-MM-DD HH:mm:ss
  • MySQL: поддерживает аналогичный формат в DATETIME
  • SQLite: более гибкий, принимает как ISO, так и SQL-формат

Поэтому toSQL выступает как компромиссный вариант между читаемостью и совместимостью.

Практические сценарии использования

Формирование диапазонов дат

const start = DateTime.local(2026, 1, 1).toSQL();
const end = DateTime.local(2026, 12, 31).toSQL();

const query = `
  SEL ECT * FR OM events
  WH ERE created_at BETWEEN '${start}' AND '${end}'
`;

Логирование событий

console.log(`[${DateTime.utc().toSQL({ includeZone: true })}] Event triggered`);

Синхронизация сервисов

При передаче данных между микросервисами SQL-формат часто используется как промежуточный:

const payload = {
  timestamp: DateTime.utc().toSQL()
};

Ограничения метода

Несмотря на удобство, метод имеет ряд ограничений:

  • не поддерживает локализацию (всегда фиксированный формат)
  • требует аккуратной работы с часовыми поясами
  • не экранирует данные для SQL
  • не заменяет параметризованные запросы

Эти особенности делают его инструментом форматирования, а не безопасности или построения запросов.