Правило: зберігати момент часу в UTC (або в типі, що зберігає саме момент), а в часовий пояс користувача перетворювати лише під час показу.
PostgreSQL:
timestamptz(timestamp with time zone) зберігає момент часу. Під час запису значення переводиться в UTC, під час читання - у пояс сесії (TimeZone). Назва вводить в оману: сам пояс не зберігається.timestamp(без поясу) - просто дата й час «на годиннику», без прив'язки до поясу. Годиться для «зустріч о 10:00 за місцевим часом», але не для моментів подій.
MySQL:
TIMESTAMPперетворюється в UTC за поясом сесії й назад, але має межу 2038 року.DATETIMEзберігає значення як є, без перетворень. Застосунок сам відповідає за те, щоб писати в UTC.
Типові проблеми:
- Сервер БД, PHP і застосунок мають різні пояси, і час «з'їжджає» на кілька годин. Явно налаштований пояс на кожному шарі прибирає цей клас багів.
- Перехід на літній час: «щодня о 02:30» за київським часом раз на рік не існує, а раз на рік буває двічі.
- Порівняння
DATE(created_at) = '2026-10-04'у UTC і в місцевому часі дає різні множини рядків.
Для майбутніх подій (запис до лікаря через пів року) інколи зберігають місцевий час і назву поясу окремо: правила поясів можуть змінитися до того моменту.