Час здається простим, поки ви не спробуєте написати програму, яка правильно його обробляє. Подія, запланована на «15:00», означає різне в Токіо, Лондоні та Нью-Йорку. Літній час переводить годинники вперед або назад — але не скрізь і не в однакові дати. Мітка часу, що виглядає правильно у вашому локальному середовищі, ламається в продакшні, бо сервер знаходиться в іншому поясі.
Часові пояси — одна з найстабільніше заплутаних тем у розробці програмного забезпечення. Ця стаття пояснює, як вони працюють, звідки береться складність і як уникнути найпоширеніших помилок.
Чому існують часові пояси
Земля обертається на 360 градусів за 24 години, що означає — сонце перебуває в найвищій точці в різні моменти залежно від вашої довготи. До XIX століття кожне місто налаштовувало годинники за місцевим сонячним часом — полудень був, коли сонце було над головою. Це працювало добре, поки залізниці не з'єднали віддалені міста і розкладу потрібен був єдиний, послідовний час.
У 1884 році делегати від 25 країн зустрілися на Міжнародній меридіанній конференції у Вашингтоні та домовилися поділити світ на 24 стандартних часових пояси, кожен зі зміщенням від нульового меридіану (0 градусів довготи), що проходить через Грінвіч, Англія.
На практиці межі часових поясів слідують за політичними кордонами, а не за рівними лініями довготи. Китай охоплює п'ять географічних поясів, але використовує єдиний офіційний час (UTC+8). Індія використовує UTC+5:30 — півгодинне зміщення. Непал використовує UTC+5:45. Реальна карта часових поясів хаотична.
UTC vs. GMT
GMT (Greenwich Mean Time) — середній сонячний час у Королівській обсерваторії в Грінвічі. Він був світовим еталоном часу понад століття.
UTC (Coordinated Universal Time) замінив GMT як міжнародний стандарт у 1972 році. UTC базується на атомних годинниках, а не на астрономічних спостереженнях, що робить його значно точнішим. Для більшості практичних цілей UTC та GMT показують однаковий час, але UTC є правильним технічним еталоном.
Чому «UTC», а не «CUT»? Абревіатура є компромісом між англійською «Coordinated Universal Time» (CUT) та французькою «Temps Universel Coordonné» (TUC). Жодна сторона не отримала бажану абревіатуру, тому UTC було обрано як мовно нейтральну альтернативу.
Літній час: організований хаос
Близько 70 країн дотримуються літнього часу (DST), переводячи годинники на одну годину вперед навесні та назад восени. Мета — узгодити робочий час зі світловим днем. Результат — піврічне джерело помилок.
Основні складнощі:
- Не універсальний. Більша частина Африки, Азії та Південної Америки не дотримується DST. У США Аризона та Гаваї відмовились.
- Різні дати. ЄС переводить годинники в останню неділю березня та жовтня. США — у другу неділю березня та першу неділю листопада. Кілька тижнів на рік вони не синхронізовані.
- Неоднозначний час. Коли годинники переводять назад, година з 1:00 до 2:00 ранку відбувається двічі. Мітка часу «1:30 ранку» в цей день неоднозначна.
- Пропущений час. Коли годинники переводять вперед, години з 2:00 до 3:00 ранку не існує. Зустріч, запланована на 2:30 ранку цього дня, ніколи не відбудеться.
- Політичні зміни. Уряди можуть (і змінюють) правила DST з невеликим попередженням. Росія прийняла постійний літній час у 2011 році, потім перейшла на постійний зимовий час у 2014 році. Марокко змінювало правила DST кілька разів.
ISO 8601: універсальний формат дати
Щоб уникнути неоднозначності, міжнародний стандарт ISO 8601 визначає чіткий формат дати та часу:
2026-03-29T14:30:00Z
2026-03-29T14:30:00+02:00
2026-03-29T14:30:00-05:00
Tрозділяє дату і час.Zозначає UTC (часовий пояс «Zulu» у військовій термінології).+02:00або-05:00— зміщення від UTC.
Цей формат однозначний, сортується як звичайний текст і універсально розуміється бібліотеками аналізу дат. Якщо сумніваєтесь, використовуйте ISO 8601.
Unix-мітки часу
Unix-мітка часу (також називається epoch time або POSIX time) — це кількість секунд, що минули з 1 січня 1970 року, 00:00:00 UTC — моменту, відомого як Unix epoch.
| Зрозумілий формат | Unix-мітка часу |
|---|---|
| 1970-01-01 00:00:00 UTC | 0 |
| 2000-01-01 00:00:00 UTC | 946684800 |
| 2026-03-29 12:00:00 UTC | 1774987200 |
Unix-мітки часу не мають часового поясу — вони завжди в UTC. Це робить їх ідеальними для зберігання та порівняння часу в програмному забезпеченні. Конвертація в місцевий часовий пояс відбувається лише на рівні відображення.
Проблема 2038 року: Системи, що зберігають Unix-мітки як 32-бітне ціле число зі знаком, переповняться 19 січня 2038 року о 03:14:07 UTC. Максимальне значення (2 147 483 647) перетвориться на від'ємне число, що інтерпретується як грудень 1901 року. Більшість сучасних систем використовують 64-бітні цілі числа, які не переповняться ще 292 мільярди років.
База даних часових поясів IANA
Програмному забезпеченню потрібні не лише зміщення UTC — воно повинно знати повну історію та майбутні правила для кожного регіону, включаючи переходи DST, політичні зміни та історичні аномалії. Ця інформація зберігається в базі даних часових поясів IANA (також відомій як база Olson або tzdata).
Вона використовує ідентифікатори на кшталт America/New_York, Europe/Paris, Asia/Tokyo. Кожен запис кодує повну історію зміщень UTC та правил DST для цієї локації.
Тому вам ніколи не слід зберігати часовий пояс як фіксоване зміщення на кшталт «+02:00». Зміщення повідомляє поточну різницю від UTC, але нічого не каже про правила DST. Europe/Paris — це UTC+1 взимку та UTC+2 влітку. Ідентифікатор IANA охоплює обидва варіанти.
Поширені помилки в програмному забезпеченні
- Зберігання місцевого часу без часового поясу. Значення на кшталт
2026-03-29 14:30:00безглузде без знання часового поясу. Завжди зберігайте UTC або вказуйте зміщення. - Припущення, що зміщення UTC дорівнює часовому поясу. UTC+2 у березні може бути UTC+3 у липні (якщо регіон дотримується DST). Зберігайте ідентифікатор IANA, а не зміщення.
- Ігнорування переходів DST при плануванні. Щоденне завдання о 2:30 ранку буде пропущене раз на рік і запущене двічі раз на рік, якщо ви не обробляєте DST.
- Припущення, що доба має 24 години. У дні переходу DST доба має 23 або 25 годин. Обчислення «завтра в цей самий час» додаванням 86 400 секунд буде помилковим на годину.
- Наївне використання JavaScript
Date.new Date("2026-03-29")аналізується як UTC в одних рушіях і як місцевий час в інших. Завжди будьте явними щодо часового поясу.
Найкращі практики для розробників
- Зберігайте час в UTC. Конвертуйте в місцевий часовий пояс користувача лише на рівні відображення.
- Використовуйте ідентифікатори часових поясів IANA (
America/New_York), а не фіксовані зміщення (-05:00). - Використовуйте ISO 8601 для серіалізації. Він однозначний і універсально парситься.
- Використовуйте зрілу бібліотеку дат. У JavaScript використовуйте
Intl.DateTimeFormatабо бібліотеку на кшталтdate-fns-tz. У Python —zoneinfo(3.9+) абоpytz. У Java —java.time.ZonedDateTime. - Тримайте
tzdataоновленою. Уряди змінюють правила DST. Вашій операційній системі та середовищу виконання потрібні актуальні дані часових поясів. - Тестуйте з кількома часовими поясами. Не припускайте, що ваш сервер і користувачі знаходяться в одному поясі.
Далі
Час оманливо складний, але правила добре задокументовані, а інструменти зрілі. Головне — поважати складність, а не ігнорувати її.
- Cron-вирази без таємниць — планування завдань у різних часових поясах
- Генератор хешів та Тестер Regex — інші інструменти для розробників на ToolK
