Как я узнал об изменениях времени на западе Советского Союза

Здесь, в Nylas, мы создаем API, чтобы помочь разработчикам создавать приложения поверх электронной почты, календаря и контактов. Как оказалось, это многому учит вас об изменении времени в западной части Советского Союза. Я присоединился к Nylas всего несколько месяцев назад и рано узнал, что одним из важных аспектов настройки события в календаре является понимание того, в каком часовом поясе находится это событие, относительно как создателя события, так и любых других участников. . Естественно, это включает в себя много математики часовых поясов. Большую часть этого делает библиотека pytz, и она работает достаточно хорошо для нас. Зачем делать самому то, что уже сделал кто-то другой, верно?

Введите Майкрософт. Многие компании используют Microsoft Exchange для своей электронной почты и рабочего календаря. Исторически Exchange использовал протокол Exchange Active Sync (EAS). Как и в случае с любым другим протоколом Microsoft, их отношение к API-интерфейсу календаря, по-видимому, было таким: «давайте предоставим все необработанные данные и заставим пользователя сделать с ними что-то полезное». Что они обеспечивают:

  • Смещение от UTC в минутах
  • Дата в этом календарном году, когда часовой пояс переходит на летнее время.
  • Дата в течение этого календарного года, когда часовой пояс переходит на стандартное время.
  • Смещение во время перехода на летнее время

… Из которого вы должны получить понятное имя, чтобы показать пользователю. Это как если бы я спросил вас о времени, и вы ответили бы, рассказав мне о прямом вращении и наклоне Земли, эксцентриситете земной орбиты, приливных эффектах Луны на скорость вращения и о том, как настроить дополнительные секунды. То есть, конечно, но не могли бы вы просто сказать мне, что сейчас 5:30?*

Pytz имеет довольно разреженный общедоступный API (где «общедоступный» определяется с использованием идиомы классов и методов Python без префикса подчеркивания). Вы, программист, создаете экземпляр объекта часового пояса из удобной строки, такой как US/Eastern, и можете использовать методы localize, normalize и utcoffset для работы с ним. Pytz заботится об отслеживании переходов и смещений DST. С точки зрения обычного пользователя это имеет смысл. Все ценностное предложение Pytz заключается в том, чтобы абстрагироваться от боли, связанной с часовыми поясами, бюрократией и политикой, связанной с изменением смещения. Но ладно, Редмонд, игра продолжается.

Мы решили использовать внутренние компоненты pytz для создания таблицы поиска для их хранения. Нам нужно использовать информацию, полученную от Microsoft, в качестве ключа и имя часового пояса в качестве значения. Для каждого часового пояса pytz хранит атрибут _utc_transition_times

>>> tz = pytz.timezone('US/Eastern') >>> pprint(tz._utc_transition_times[-5:]) [datetime.datetime(2035, 11, 4, 6, 0), datetime.datetime(2036, 3, 9, 7, 0), datetime.datetime(2036, 11, 2, 6, 0), datetime.datetime(2037, 3, 8, 7, 0), datetime.datetime(2037, 11, 1, 6, 0)]

О, круто, значит, мы можем использовать это для создания таблицы поиска, верно? Мы возьмем первый переход данного года как переход на летнее время, второй переход данного года как переход на летнее время, выберем время вне летнего времени и найдем смещение UTC, и сохраним кортеж этого как ключ от нашего стола!

>>> daylight_time = tz._utc_transition_times[n] >>> standard_time = tz._utc_transition_times[n+1] >>> utc_offset = tz.utc_offset(date_not_in_dst) >>> timezone_table[(daylight_time, standard_time, utc_offset)] = timezone_name

Это работало хорошо, пока мы не получили сообщение об ошибке, что события календаря в Окленде теряли информацию о часовом поясе. Изучив это, оказалось, что в нашей таблице поиска были обратные записи daylight_time и standard_time . Как это могло произойти? Что ж, оказывается, мы сделали очень плохое предположение, когда предположили, что первый переход в году — это переход на летнее время. Поскольку лето в Южном полушарии длится с декабря по март, они переходят на летнее время примерно в ноябре и выходят примерно в апреле следующего года. Возможно, Картографы за социальное равенство были правы! Мы не осознавали этой разницы между Северным и Южным полушариями и из-за этого ошибались. Вернуться к доске для рисования.

Копаем в Питце

Итак, необходимо немного больше покопаться в Pytz. Как именно работает эта библиотека? Оказывается, это действительно увлекательно. Вместе с кодовой базой поставляется база данных Olson, также известная как база данных Zoneinfo или tz. Вся база данных написана в стиле Unix с файлами открытого текста, описывающими названия часовых поясов и исторические смещения для каждого географического региона. Но еще более заметными, чем фактические данные, являются все исторические анекдоты и контекст, разбросанные повсюду в виде комментариев. Некоторые из них большие, некоторые маленькие, а некоторые кажутся только внутренними шутками между сопровождающими.

Например, на Аляске:

От Пола Эггерта (2017–06–15):

…Многие жители Аляски не знали о приобретении Аляски США, не говоря уже о каких-либо изменениях календаря или времени. Однако в части Аляски, находящейся под влиянием России, соблюдалось русское время, и правильнее смоделировать это, чем игнорировать. Формат базы данных требует точного времени перехода; использовать русский салют как несколько произвольное время для формальной передачи контроля над всей Аляской. Смещение UTC Ситки составляет -9:01:13; настройте его 15:30 на местное время других мест на Аляске, чтобы они менялись одновременно.

От Пола Эггерта (2014–07–18):

Одно мнение о беспорядках начала 1980-х на Аляске из-за часовых поясов и перехода на летнее время появилось в виде граффити на стене аэропорта Джуно:

«Добро пожаловать в Джуно. Пожалуйста, переведите свои часы в 19 век».

См.: Тернер В. Четыре часовых пояса Аляски теперь два. NY Times 1983–11–01 http://www.nytimes.com/1983/11/01/us/alaska-s-four-time-zones-now-two.html

И в Мичигане:

От Пола Эггерта (1999–03–31):

Шанкс пишет, что Мичиган начал использовать стандартное время в 1885–09–1818 годах, но Хауз пишет (стр. 124–125, ссылаясь на Popular Astronomy, 1901–01), что Детройт пользовался местным временем до 1900 года, когда городской совет постановил, что часы должны быть установлены. назад двадцать восемь минут по центральному поясному времени. Половина города подчинилась, половина отказалась. После долгих дебатов решение было отменено, и город вернулся к солнечному времени. Насмешливое предложение установить солнечные часы перед ратушей было передано в Комитет по канализации. Затем, в 1905 году, городским голосованием было принято центральное время.

Эта история слишком занимательна, чтобы быть ложной, так что выбирайте Хауза, а не Шанкса.

Часовые пояса политичны — кто знал? Шутки в сторону, я хотел посмотреть, как на самом деле pytz справляется со временем. Это происходит в методе localize класса часового пояса. localize пытается охватить все основания для странных переходов часовых поясов. Для этого он делит пополам _utc_transition_times, чтобы найти, где в списке переходов находится заданное время. Затем он извлекает информацию о переходе с _transition_info.

>>> tz = pytz.timezone('US/Eastern') >>> pprint(tz._utc_transition_times[:5]) [datetime.datetime(1, 1, 1, 0, 0), datetime.datetime(1901, 12, 13, 20, 45, 52) datetime.datetime(1918, 3, 31, 7, 0), datetime.datetime(1918, 10, 27, 6, 0), datetime.datetime(1919, 3, 30, 7, 0)] >>> pprint(tz._transition_info[:5]) [(datetime.timedelta(-1, 68640), datetime.timedelta(0), 'LMT'), (datetime.timedelta(-1, 68400), datetime.timedelta(0), 'EST'), (datetime.timedelta(-1, 72000), datetime.timedelta(0, 3600), 'EDT'), (datetime.timedelta(-1, 68400), datetime.timedelta(0), 'EST'), (datetime.timedelta(-1, 72000), datetime.timedelta(0, 3600), 'EDT')]

Это рассказывает гораздо лучшую историю. Для каждой записи в _utc_transition_times есть соответствующая запись в _transition_info. Смещение DST в этой записи говорит нам, является ли это переходом к ST (если он равен нулю) или DST (если это не так). Кроме того, смещение UTC можно использовать напрямую, а не требовать эталонного времени для проверки.

Итак, каковы крайние случаи здесь? Что ж, оказывается, когда вы используете информацию о часовом поясе для идентификации имени, существует несколько возможных записей. Возможно, вас не удивит, что существуют разные названия часовых поясов, представляющих Москву и Турцию. Но если вы не будете осторожны, то легко заменить «Европа/Москва» или «Европа/Стамбул» (обычное представление этого часового пояса) на «W-SU» (для Западной части Советского Союза).

Кроме того, просто взглянув на метод localize, можно увидеть целый ряд пограничных случаев. Существует, казалось бы, очевидный случай попытки иметь дело со временем внутри перехода, например. 1:30 утра в день перехода с летнего времени на стандартное время — это время до или после перехода? Но есть и другие случаи, когда страны переводят свои часы назад вне перехода на летнее время. Это может вызвать проблемы у тех, кто пытается выполнять преобразования в реальном времени между часовыми поясами.

К счастью, в этом мы можем положиться на pytz. Хотя это и не идеально, pytz охватывает как можно больше крайних случаев при решении одной из самых серьезных проблем для программирования. Хотя нам нужно работать с более тонкими моментами перехода часовых поясов для расшифровки событий Exchange, мы обычно можем просто использовать прекрасный API pytz в другом месте.

Если вы хотите узнать больше об API календаря Nylas, вы можете получить бесплатный ключ API, зарегистрировавшись здесь.

Первоначально опубликовано на www.nylas.com.