Red Hot Chili Python

Время, UTC, GMT и много проблем

«  EncFS   ::   Contents   ::   Опыт использования MongoDB для подсчета статистики  »

Время, UTC, GMT и много проблем

Warning

Этот пост находится в процессе написания. Прошу его не читать. Когда я закончу – пост попадёт в вашу рсс-ленту (и я наверняка напишу о нём на всякие хабры).

Работа со временем – вещь, с которой следует разобраться, пока еще не поздно.

Литература для просветления

Для начала неплохо почитать Как перестать думать о часовых поясах и начать жить, или лучше сразу выдержку из комментария к тому топику:

Автор статьи находится ровно на 1 шаг впереди вас в понимании того, о чем он писал. Если вы будете перечитывать это «до полного понимания», то вы просто заполните собственную голову тем… набором неупорядоченных фактов, который в голове у него. Суть статьи я бы изложил гораздо короче:

  1. При нахождении времени часовом поясе (временной зоне, time zone) A по времени в часовом поясе B удобно пользоваться в качестве посредника универсальным временем, которое одно и то же в любой точке Земли и даже в космосе. Оно называется всемирным координированным временем (Universal Coordinated Time, UTC).
  2. В Unix и многих языках программирования ряд функций возвращают и принимают в качестве аргумента время UTC не в удобном для человека виде (17:20 5 сентября 2001 года), а в виде, удобном для компьютера — в виде числа секунд, прошедших с условного начала «эпохи Unix» (полночь 1 января 1970 г.) Обычно это целое число, помещающееся в 32-битный регистр микропроцессора. Такое число называют Unix timestamp или просто Unix time.
  3. UTC отсчитывается атомными часами. Иногда, чтобы привести в соответствие UTС времени, получаемому из астрономических наблюдений, в него вводят так называемые leap seconds (аналогичные leap years — високосным годам), когда последняя минута в году состоит не из 60, а из 61 секунды.
  4. Для времени, получаемого из астрономических наблюдений (всемирное время, UT), раньше использовалась другая аббревиатура — GMT (Greenwich Mean Time, cреднее гринвичское время). Она является анахронизмом, совершенно не нужна программисту, и ее использование является признаком дурного тона и плохой осведомленности программиста о стандартах времени. Для тех, кто не понимает по-русски: GMT is deprecated.

Это практически всё, что нужно знать программисту. Разглагольствовать о том, когда солнце пересекает меридиан, нелепо, потому что ни автор статьи, ни 98% читающих это не смогут сказать, что такое небесный меридиан.

Вот так вот.

Ну а теперь, собственно, стоит пойти и почитать большой пост от Андрея Светлова о работе с датами из Питона (и различными проблемами): Питон: времена, даты и временные зоны.

Небольшой итог

Приведу только “итоги” из записи Андрея:

  • Старайтесь работать с абсолютными временами.
  • Для общения с внешним миром предпочитайте UTC.
  • Если по каким-то причинам вам приходится иметь дело с относительным временем - сокращайте такие моменты до минимума, возвращаясь к абсолютным временам сразу же как только возможно.
  • Помните: ввести абсолютные времена на разросшийся и уже массово использующийся проект стоит чрезвычайно дорого.

С точки зрения питона

С точки зрения питона, я лично, еще раз взглянул на работу с датами и осознал, что вещи стоит делать немного по-другому. К примеру, получить datetime для 00:00 сегодняшнего дня в UTC с таймзоной –

import datetime
import pytz
today = datetime.datetime.now(pytz.utc).replace(hour=0, minute=0, second=0, microsecond=0)

Note

Зачем мне нужен datetime с 00:00 сегодняшнего дня? Потому что именно так MongoDB хранит даты, в datetime. И отдаёт их так же в datetime. Второй вариант, конечно, – хранить даты в “YYYY-MM-DD”, но мне кажется это глупостью, потому что потом лишний раз преобразовывать придется.

Потом я осознал, что datetime.date не осведомлён о таймзоне (и не может быть, как будто у всех стран следующий день наступает одновременно).

Даты в JavaScript (ну и MongoDB)

Warning

Это очень важно! В JavaScript у new Date(y, m, d) второй параметр (месяц) бывает от 0 до 11ти (а не 1-12).

Если в кратце:

// 10 мая (05!) 2011
var d = new Date(Date.UTC(2011, 5-1, 10))

В MongoDB даты хранятся в осведомлённом UTC (aware), потому что рисуются с буквой Z на конце, но pymongo по-умолчанию это игнорирует и при выборке/вставке оперирует с datetime без таймзоны.

Но pymongo.connection.Connection умеет принимать параметр tz_aware=True, тогда, похоже, можно пользоваться aware-датами (я не пробовал, но верю).

Todo

дописать

«  EncFS   ::   Contents   ::   Опыт использования MongoDB для подсчета статистики  »

blog comments powered by Disqus