Как преобразовать строку в дату в 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в MySQLparseDateTimeBestEffortв ClickHousePARSE_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+ вопросами для собесов.