Пошук уроків, статей та іншого контенту
Навчитеся працювати з датами, часом, часовими поясами та перетвореннями між часовими типами.
PostgreSQL має кілька типів для збереження дат і часу:
date — календарна дата без часу;
time — час доби без дати;
timestamp — дата й час без часового поясу;
timestamptz — дата й час із часовим поясом;
time with time zone — час доби з часовим поясом, використовується рідше.
Найчастіше в прикладних програмах достатньо таких типів:
date для дат народження, дедлайнів і свят;
timestamp для локального часу, якщо часовий пояс не має значення;
timestamptz для моментів часу: створення запису, оплати, входу користувача.
dateТип date зберігає лише календарну дату:
SELECT DATE '2026-09-01' AS lesson_date;Результат:
lesson_date
-------------
2026-09-01Дата має формат:
YYYY-MM-DDде:
YYYY — рік;
MM — місяць;
DD — день.
Можна створити таблицю з датою:
CREATE TEMP TABLE tasks (
title text,
due_date date
);
INSERT INTO tasks (title, due_date)
VALUES
('Підготувати звіт', DATE '2026-09-10'),
('Перевірити домашнє завдання', DATE '2026-09-15');
SELECT title, due_date
FROM tasks
ORDER BY due_date;timeТип time зберігає час доби без дати:
SELECT TIME '14:30:00' AS start_time;Час може містити дробову частину секунди:
SELECT TIME '14:30:15.250' AS precise_time;У таблиці цей тип може бути корисним для щоденного розкладу:
CREATE TEMP TABLE schedule (
event_name text,
start_time time
);
INSERT INTO schedule (event_name, start_time)
VALUES
('Ранкова нарада', TIME '09:00'),
('Перерва', TIME '13:30');
SELECT event_name, start_time
FROM schedule
ORDER BY start_time;time не містить інформації про дату або часовий пояс. Значення 09:00 може означати різний момент часу залежно від дня та часового поясу.
timestamptimestamp без уточнення — це timestamp without time zone. Він зберігає дату й час, але не зберігає часовий пояс:
SELECT TIMESTAMP '2026-09-01 14:30:00' AS local_time;Таке значення означає:
1 вересня 2026 року о 14:30
Але не вказує, де саме: у Києві, Лондоні чи Нью-Йорку.
Тип timestamp підходить, коли часовий пояс не потрібен. Наприклад:
час відкриття магазину, який завжди вказують у локальному часі;
час початку події в календарі конкретного офісу;
дата й час, що мають значення лише в межах однієї часової зони.
timestamptztimestamp with time zone, скорочено timestamptz, призначений для збереження конкретного моменту часу:
SELECT TIMESTAMPTZ '2026-09-01 14:30:00+03' AS event_time;Позначення +03 означає зміщення часового поясу на три години вперед від UTC.
PostgreSQL нормалізує значення timestamptz до моменту часу. Під час виведення він показує цей момент у часовому поясі поточної сесії.
Наприклад:
SET TIME ZONE 'Europe/Kyiv';
SELECT TIMESTAMPTZ '2026-09-01 14:30:00+03' AS kyiv_time;
SET TIME ZONE 'UTC';
SELECT TIMESTAMPTZ '2026-09-01 14:30:00+03' AS utc_time;Це той самий момент часу, але він відображається по-різному залежно від часового поясу сесії.
Важливо: timestamptz не зберігає назву часового поясу на кшталт Europe/Kyiv. Він зберігає момент часу, а часовий пояс використовується для введення та відображення значення.
PostgreSQL надає спеціальні значення для поточного часу:
SELECT
CURRENT_DATE AS today,
CURRENT_TIME AS current_time,
CURRENT_TIMESTAMP AS current_timestamp,
NOW() AS current_time_again;CURRENT_TIMESTAMP і NOW() повертають значення типу timestamptz.
Для таблиць часто використовують значення за замовчуванням:
CREATE TEMP TABLE messages (
body text,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO messages (body)
VALUES ('Перше повідомлення');
SELECT body, created_at
FROM messages;Якщо під час вставки не вказати created_at, PostgreSQL встановить поточні дату й час.
Поточний часовий пояс можна переглянути так:
SHOW TIME ZONE;Змінити його для поточного підключення можна командою:
SET TIME ZONE 'Europe/Kyiv';Також можна вказати часовий пояс як зміщення:
SET TIME ZONE 'UTC';Налаштування діє лише для поточної сесії бази даних. Воно впливає на:
відображення значень timestamptz;
інтерпретацію деяких текстових значень дат і часу;
результат функцій, що повертають поточний час.
Для позначення часового поясу можна використовувати:
зміщення: +03, -05:00;
назву зони: 'Europe/Kyiv', 'UTC'.
Приклад зі зміщенням:
SELECT TIMESTAMPTZ '2026-09-01 14:30:00+03';Для перетворення моменту часу в локальний час певної зони використовується AT TIME ZONE:
SELECT
TIMESTAMPTZ '2026-09-01 14:30:00+03'
AT TIME ZONE 'UTC' AS utc_time,
TIMESTAMPTZ '2026-09-01 14:30:00+03'
AT TIME ZONE 'America/New_York' AS new_york_time;У цьому випадку результатом буде timestamp without time zone, тобто локальна дата й час у вказаній зоні.
Назви часових зон важливі, оскільки вони враховують правила переходу на літній і зимовий час. Зміщення +03 саме по собі не містить таких правил.
timestamp і timestamptzРозглянемо два значення:
SELECT
TIMESTAMP '2026-09-01 14:30:00' AS without_zone,
TIMESTAMPTZ '2026-09-01 14:30:00+03' AS with_zone;timestamp означає лише локальну дату й час:
2026-09-01 14:30:00timestamptz означає конкретний момент, який відповідає:
2026-09-01 11:30:00 UTCЯкщо застосунок працює з подіями, які мають бути синхронізованими для користувачів у різних країнах, зазвичай використовують timestamptz.
До дати можна додавати або віднімати цілі числа. Число означає кількість днів:
SELECT
DATE '2026-09-01' + 7 AS next_week,
DATE '2026-09-01' - 1 AS previous_day;Для більш гнучких операцій використовується interval:
SELECT
DATE '2026-09-01' + INTERVAL '2 months' AS after_two_months,
TIMESTAMP '2026-09-01 14:30:00' + INTERVAL '3 hours' AS later_time;Віднімання двох дат повертає кількість днів:
SELECT DATE '2026-09-10' - DATE '2026-09-01' AS days_between;Результат:
days_between
--------------
9Віднімання двох значень часу повертає інтервал:
SELECT
TIMESTAMP '2026-09-01 18:00:00'
- TIMESTAMP '2026-09-01 14:30:00' AS duration;Функція EXTRACT дає змогу отримати окрему частину значення:
SELECT
EXTRACT(YEAR FROM TIMESTAMP '2026-09-01 14:30:15') AS year,
EXTRACT(MONTH FROM TIMESTAMP '2026-09-01 14:30:15') AS month,
EXTRACT(DAY FROM TIMESTAMP '2026-09-01 14:30:15') AS day,
EXTRACT(HOUR FROM TIMESTAMP '2026-09-01 14:30:15') AS hour;Також можна використовувати функцію date_part:
SELECT date_part(
'month',
TIMESTAMP '2026-09-01 14:30:15'
) AS month_number;Для округлення до певної частини часу використовується date_trunc:
SELECT
date_trunc('day', TIMESTAMP '2026-09-01 14:30:15') AS start_of_day,
date_trunc('month', TIMESTAMP '2026-09-01 14:30:15') AS start_of_month;Результат буде приблизно таким:
start_of_day | start_of_month
---------------------+---------------------
2026-09-01 00:00:00 | 2026-09-01 00:00:00Для явного перетворення використовують оператор CAST або скорочений запис ::.
Перетворення timestamp на date відкидає час:
SELECT
CAST(TIMESTAMP '2026-09-01 14:30:15' AS date) AS only_date,
TIMESTAMP '2026-09-01 14:30:15'::date AS only_date_again;Перетворення date на timestamp додає час 00:00:00:
SELECT DATE '2026-09-01'::timestamp AS date_with_midnight;Перетворення тексту на дату:
SELECT '2026-09-01'::date AS parsed_date;Для надійного коду краще використовувати стандартний формат YYYY-MM-DD і явно вказувати тип:
SELECT DATE '2026-09-01';Наведений приклад можна виконати в PostgreSQL як один скрипт:
-- Встановлюємо часовий пояс поточного підключення
SET TIME ZONE 'Europe/Kyiv';
CREATE TEMP TABLE orders (
order_number integer,
ordered_at timestamptz NOT NULL,
delivery_date date NOT NULL
);
INSERT INTO orders (order_number, ordered_at, delivery_date)
VALUES
(1001, TIMESTAMPTZ '2026-09-01 09:15:00+03', DATE '2026-09-03'),
(1002, TIMESTAMPTZ '2026-09-01 16:40:00+03', DATE '2026-09-05');
SELECT
order_number,
ordered_at,
ordered_at AT TIME ZONE 'UTC' AS ordered_at_utc,
delivery_date,
delivery_date - CURRENT_DATE AS days_until_delivery
FROM orders
ORDER BY ordered_at;У запиті:
ordered_at зберігає конкретний момент часу;
AT TIME ZONE 'UTC' показує цей момент у форматі UTC;
delivery_date зберігає лише календарну дату;
віднімання дат показує кількість днів до доставки.
Дати та часові значення можна порівнювати звичайними операторами:
SELECT *
FROM orders
WHERE delivery_date >= DATE '2026-09-04';Для діапазону дат зручно використовувати дві умови:
SELECT *
FROM orders
WHERE delivery_date >= DATE '2026-09-01'
AND delivery_date < DATE '2026-09-06';Такий запис однозначно задає напіввідкритий діапазон: від початку 1 вересня до початку 6 вересня.
Для timestamptz порівняння відбувається за моментами часу, а не за текстовим виглядом значень:
SELECT *
FROM orders
WHERE ordered_at >= TIMESTAMPTZ '2026-09-01 00:00:00+03'
AND ordered_at < TIMESTAMPTZ '2026-09-02 00:00:00+03';timestamp для глобальних подійЯкщо зберігати час оплати або створення повідомлення як timestamp, часовий пояс буде втрачено.
Для таких даних краще використовувати:
created_at timestamptztimestamptztimestamptz не означає, що PostgreSQL збереже назву часового поясу користувача. Тип зберігає момент часу, а показує його відповідно до часового поясу поточної сесії.
Якщо потрібно знати, яку саме зону обрав користувач, її можна зберігати окремо, наприклад у текстовому полі.
Не варто передавати значення без пояснення, чи це UTC, чи локальний час:
2026-09-01 14:30:00Краще явно вказувати часовий пояс для моментів часу:
2026-09-01 14:30:00+03time для моменту подіїЗначення TIME '14:30' не визначає конкретний момент часу. Воно не містить ні дати, ні часового поясу.
Для запланованої події зазвичай потрібна комбінація дати й часу, а для глобальної системи — timestamptz.
timestamptz на date без урахування зониПід час перетворення timestamptz на date PostgreSQL використовує часовий пояс поточної сесії:
SET TIME ZONE 'Europe/Kyiv';
SELECT TIMESTAMPTZ '2026-09-01 22:30:00+00'::date;Той самий момент у Києві вже може належати наступній календарній даті, ніж у UTC. Тому перед отриманням дати важливо встановити потрібний часовий пояс або явно застосувати AT TIME ZONE.
date зберігає календарну дату без часу.
time зберігає час доби без дати.
timestamp зберігає дату й час без часового поясу.
timestamptz зберігає конкретний момент часу.
Часовий пояс сесії впливає на відображення timestamptz.
AT TIME ZONE дає змогу показати момент часу в іншій часовій зоні.
interval використовується для додавання та віднімання проміжків часу.
Для глобальних подій зазвичай варто обирати timestamptz.
Для локальних календарних значень без прив’язки до моменту часу підходить timestamp або date.