Даты и время: вопросы для собеседования (часть 4)

Работа с датами в SQL — это DATE_TRUNC, EXTRACT, интервалы, приведение типов и группировка по временным периодам. На собеседованиях часто просят посчитать метрику по неделям или месяцам, найти разницу между датами, или отфильтровать данные за скользящее окно. Ошибки в работе с таймзонами и форматами дат — частая причина провала на интервью.

Агрегация, GROUP BY и HAVINGEXPLAIN и оптимизацияВыражения и NULLJOIN и операции множествОсновы SQL-запросовСтроки и приведение типовПодзапросы и CTEОконные функции

Вопросы 1620 из 20

16Какое описание лучше всего соответствует типу `timestamptz` в PostgreSQL?
AЭто строка, в которой всегда хранится исходная таймзона пользователя.
BЭто тип, который хранит момент времени, а при выводе учитывает таймзону (настройку сессии или указанную явно).
CЭто тип `date`, но с более точным форматом хранения.
DЭто тип, который нельзя сравнивать и сортировать.
Ответ: `timestamptz` описывает момент времени; отображение/приведение зависит от таймзоны.

`timestamptz` хранит абсолютный момент времени. При отображении и некоторых преобразованиях используется таймзона сессии или указанная в выражении. В отличие от `timestamp` без таймзоны, `timestamptz` помогает корректно работать с событиями из разных регионов.

17Нужно отобрать события ровно за вчерашний календарный день по `created_at` типа `timestamp`, чтобы не задвоить границы при ежедневном запуске. Какое условие в `WHERE` лучше?
A`WHERE created_at >= current_timestamp - INTERVAL '24 hours' AND created_at < current_timestamp`
B`WHERE created_at > current_date - INTERVAL '1 day' AND created_at <= current_date`
C`WHERE created_at >= current_date - INTERVAL '1 day' AND created_at < current_date`
D`WHERE created_at BETWEEN current_date - INTERVAL '1 day' AND current_date`
Ответ: Для календарного дня используйте полуинтервал `[start, end)` на базе `current_date`.

Удобнее задавать границы как `created_at >= start AND created_at < end`. Тогда событие ровно на границе (например, в `00:00:00`) попадёт только в один день и не будет задваиваться, в отличие от `BETWEEN`, который включает обе границы.

18Колонка `created_at` типа `timestamptz`. Как получить дату события в UTC (тип `date`), чтобы результат не зависел от таймзоны сессии?
A`created_at::date`
B`(created_at AT TIME ZONE 'Europe/Moscow')::date`
C`DATE_TRUNC('day', created_at)::date`
D`(created_at AT TIME ZONE 'UTC')::date`
Ответ: Приведение `timestamptz` к `date` зависит от таймзоны; для UTC сначала используйте `AT TIME ZONE 'UTC'`.

Когда вы делаете `created_at::date`, PostgreSQL сначала переводит `timestamptz` в локальное время таймзоны сессии, затем отбрасывает время. Чтобы получить UTC-дату, явно переведите момент времени в UTC: `(created_at AT TIME ZONE 'UTC')::date`.

19Колонка `created_at` типа `timestamptz`. Таймзона сессии (`TimeZone`) может отличаться между задачами. Как гарантированно сгруппировать события по UTC-дням?
A`DATE_TRUNC('day', created_at)`
B`DATE_TRUNC('day', created_at::timestamp)`
C`DATE_TRUNC('day', created_at AT TIME ZONE 'Europe/Moscow')`
D`DATE_TRUNC('day', created_at AT TIME ZONE 'UTC')`
Ответ: Для стабильных UTC-бакетов на `timestamptz` явно переводите время в UTC перед `DATE_TRUNC`.

Операции над `timestamptz` могут зависеть от таймзоны сессии. Если отчёт должен считать дни строго по UTC, сначала приведите момент времени к UTC через `created_at AT TIME ZONE 'UTC'`, затем применяйте `DATE_TRUNC('day', ...)`.

20В таблице `events(user_id, created_at)` колонка `created_at` типа `timestamptz` (события записаны в UTC). Нужно посчитать DAU по дням в таймзоне Москвы (и не зависеть от таймзоны сессии). Какой бакет правильный?
A`DATE_TRUNC('day', created_at)`
B`DATE_TRUNC('day', created_at::timestamp)`
C`DATE_TRUNC('day', created_at AT TIME ZONE 'Europe/Moscow')`
D`DATE_TRUNC('day', created_at AT TIME ZONE 'UTC')`
Ответ: Для локальных дней сначала переведите метку времени в нужную таймзону, затем применяйте `DATE_TRUNC`.

Если нужно группировать события по дням в конкретной таймзоне, сначала приведите `timestamptz` к локальному времени через `AT TIME ZONE`, а затем бакетируйте `DATE_TRUNC('day', ...)`. Иначе результат может зависеть от настроек таймзоны сессии или останется в UTC.

1234

Хотите тренировать интерактивно?

В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.

Тренировать в Telegram

Другие темы: SQL

Агрегация, GROUP BY и HAVINGEXPLAIN и оптимизацияВыражения и NULLJOIN и операции множествОсновы SQL-запросовСтроки и приведение типовПодзапросы и CTEОконные функции