Как преобразовать строку в дату в SQL

Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.

Зачем это нужно аналитику

Даты в базе не всегда хранятся как DATE. Из CSV даты приходят строками, из стороннего API — в ISO формате с таймзоной, из Excel — в формате DD.MM.YYYY. Пока эти строки лежат как VARCHAR, вы не можете сделать WHERE created_at > NOW() - INTERVAL '7 days', сгруппировать по месяцам или посчитать разницу между двумя датами.

Плюс сравнение дат как строк — классический баг: '22.04.2026' > '01.05.2026' вернёт TRUE, потому что строки сравниваются посимвольно. Умение правильно преобразовать строку в дату — базовый навык для работы с грязными данными.

В статье — готовые рецепты для всех популярных СУБД:

  • TO_DATE в Postgres с маской формата
  • STR_TO_DATE в MySQL
  • parseDateTimeBestEffort в ClickHouse
  • PARSE_DATE в BigQuery, TO_DATE в Snowflake
  • Обработка невалидных дат (NULL вместо ошибки)
  • Unix timestamp → DATE
  • Массовая миграция через новую колонку + индекс

Задача

Колонка date_str = '22.04.2026' — строка. Нужно превратить в DATE для работы с интервалами и сортировкой.

PostgreSQL

TO_DATE (основная функция)

SELECT TO_DATE('22.04.2026', 'DD.MM.YYYY');     -- 2026-04-22
SELECT TO_DATE('2026-04-22', 'YYYY-MM-DD');
SELECT TO_DATE('22/04/2026', 'DD/MM/YYYY');
SELECT TO_DATE('22 Apr 2026', 'DD Mon YYYY');

TO_TIMESTAMP (для дат + времени)

SELECT TO_TIMESTAMP('2026-04-22 10:30:00', 'YYYY-MM-DD HH24:MI:SS');

Автоматический cast

Для ISO-формата работает автоматически:

SELECT '2026-04-22'::DATE;                          -- работает
SELECT '2026-04-22 10:30:00'::TIMESTAMP;            -- работает
SELECT CAST('2026-04-22' AS DATE);                  -- работает

Для других форматов cast не работает — нужна TO_DATE.

MySQL

STR_TO_DATE

SELECT STR_TO_DATE('22.04.2026', '%d.%m.%Y');       -- 2026-04-22
SELECT STR_TO_DATE('2026-04-22', '%Y-%m-%d');
SELECT STR_TO_DATE('22/04/2026', '%d/%m/%Y');
SELECT STR_TO_DATE('Apr 22, 2026', '%b %d, %Y');

ClickHouse

SELECT toDate('2026-04-22');                        -- авто для ISO
SELECT parseDateTimeBestEffort('22.04.2026');       -- пытается угадать формат
SELECT parseDateTime32('22.04.2026 10:30:00', '%d.%m.%Y %H:%M:%S');

BigQuery

SELECT PARSE_DATE('%d.%m.%Y', '22.04.2026');
SELECT PARSE_DATETIME('%d.%m.%Y %H:%M', '22.04.2026 10:30');

Snowflake

SELECT TO_DATE('22.04.2026', 'DD.MM.YYYY');
SELECT TO_TIMESTAMP('22.04.2026 10:30:00', 'DD.MM.YYYY HH24:MI:SS');

Маска формата

Postgres

Код Значение
YYYY 4-значный год
YY 2-значный
MM месяц (01-12)
Mon Jan, Feb, ...
Month January, February, ...
DD день (01-31)
Day Monday, Tuesday, ...
HH24 час 0-23
HH12 час 1-12
MI минута
SS секунда
MS миллисекунда
US микросекунда

MySQL

Код Значение
%Y 4-значный год
%y 2-значный
%m месяц (01-12)
%c месяц (1-12, без нуля)
%d день (01-31)
%e день (1-31)
%H час 0-23
%h час 1-12
%i минута
%s секунда
%b Jan, Feb, ...
%W полный день недели

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

Postgres

-- упадёт на '32.04.2026'
SELECT TO_DATE('32.04.2026', 'DD.MM.YYYY');

-- defensive coding
SELECT CASE
    WHEN date_str ~ '^\d{2}\.\d{2}\.\d{4}$'
    THEN TO_DATE(date_str, 'DD.MM.YYYY')
    ELSE NULL
END FROM data;

MySQL

-- STR_TO_DATE возвращает NULL для invalid
SELECT STR_TO_DATE('32.04.2026', '%d.%m.%Y');  -- NULL (не ошибка)

-- фильтр
SELECT * FROM data WHERE STR_TO_DATE(date_str, '%d.%m.%Y') IS NOT NULL;

Массовое преобразование

-- Postgres: добавить колонку и заполнить
ALTER TABLE events ADD COLUMN event_date DATE;

UPDATE events
SET event_date = TO_DATE(date_str, 'DD.MM.YYYY')
WHERE date_str IS NOT NULL;

-- создать индекс после
CREATE INDEX idx_events_date ON events(event_date);

Unix timestamp → date

Postgres

SELECT TO_TIMESTAMP(1734556800);  -- из секунд
SELECT TO_TIMESTAMP(1734556800)::DATE;

MySQL

SELECT FROM_UNIXTIME(1734556800);
SELECT DATE(FROM_UNIXTIME(1734556800));

Частые ошибки

1. Перепутанный формат

DD/MM/YYYY vs MM/DD/YYYY — разные страны, разные традиции. Всегда уточняйте.

2. Двузначный год

'26' → 2026 или 1926? В Postgres YY → 2026 (2000+).

3. Nulls при несовпадении формата

В MySQL STR_TO_DATE тихо возвращает NULL. Проверяйте на NULL после преобразования.

4. Performance

TO_DATE на миллионах строк — медленно. Один раз преобразуйте в отдельную колонку + индекс.

5. Timezone

TIMESTAMP без зоны vs с зоной. Для дат обычно достаточно DATE, зоны не нужны.

Связанные темы

FAQ

TO_DATE или CAST?

Для ISO-формата работает оба. Для нестандартного — только TO_DATE / STR_TO_DATE с форматом.

Как обработать миллионы строк?

Добавить новую колонку DATE, обновить UPDATE, создать индекс.

Что делать с плохими данными?

CASE WHEN regex_match THEN TO_DATE ELSE NULL END.

Unix timestamp в секундах или миллисекундах?

Зависит от источника. Postgres TO_TIMESTAMP — секунды. Для ms делите на 1000.


Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.