Я потратил день на разбирательство, почему на сервере часы начали прыгать туда-сюда на 3 часа. Этот текст написан в расчёте на то, что другие его найдут и сэкономят время.

Проблема

Если где-нибудь в "потрохах" вашего (или того, который неявно используется, о котором вы даже особо не задумывались) кода на Python есть вот такой вот код:
import datetime
dt = datetime.datetime(2019,11,16,9)
n = dt.strftime('%s')

то она больше не будет работать так, как раньше.

Да, %s - недокументированная возможность, не надо её использовать. Но иногда она появляется в коде. Если своём, то можно такое вычистить. Если чужом, то начинается возня с патчами.

Почему?

Потому, что 50 лет назад при создании ОС Unix никто не думал о часовых поясах. А потом, когда придумали,
сделали это на скорую руку. А потом разработчики операционных систем развили это, добавив нестандартные поля и слегка изменив семантику. А разработчики интерпретаторов не только написали свои библиотеки по спецификации, но и зафиксировали поля в спецификации своего языка программирования.

Как работает datetime.strftime?

Python - один из языков, в котором не стали переписывать код из libc, а просто вызываюют
стандартные функции "сишной" библиотеки libc. Так делают не все. При вызове strftime объект datetime формирует кортеж с полями для структуры tm, описанной по стандарту POSIX. Вот тут, https://github.com/python/cpython/blob/v3.12.5/Modules/_datetimemodule.c см. datetime_timetuple.

В этот момент информация о часовом поясе необратимо теряется. Есть только летнее / зиимнее время и больше ничего. Но по семантике кортеж хранит время в текущем часовом поясе, что бы это ни значило. Передать часовой пояс невозможно, докумментация Python фиксирует количество полей кортежа и их семантику для time.strftime.

Потом этот кортеж передаётся другому модулю-обёртке вокруг libc - time. Там он распаковывается и передаётся уже в сишную библиотечную функцию strftime. См. тут https://github.com/python/cpython/blob/v3.12.5/Modules/timemodule.c В этот момент дополнить кортеж данными о часовом поясе невозможно: можно часовой пояс вычислить, но надёжно узнать, каким он был на предыдущем шаге уже непросто.

Потом он попадает в libc. Вот сюда: https://cgit.freebsd.org/src/tree/lib/libc/stdtime/strftime.c?h=releng%2F14.1.
Раньше (см. https://cgit.freebsd.org/src/commit/lib/libc/stdtime?id=46c599340f187db577b9212ab18022f3c7380c68 ) там просто вызывали mktime и интерпретировали время в текущем часовом поясе процесса (в соответствии с переменной окружения TZ). Но теперь используют поле tm_gmtoff, которого в стандарте POSIX нет. И делают поправку на часовой пояс.

А почему так сделали?

Полгода назад Dag-Erling Smørgrav написал (см. https://mm.icann.org/pipermail/tz/2024-January/033488.html), что нехорошо, что strftime('%s') для одного и того же времени даёт разный результат в зависимости от того, как именно это время было распаковано из time_t в struct tm, через localtime или через gmtime. В принципе, он прав, нехорошо. Чтобы strftime давала одинаковую строчку для одного и того же времени, ей придётся читать одно из дополнительных полей. И она теперь читает.

По мне так можно было прочитать ещё одно поле, которое там всё равно есть (tm_zone) и не поломать Python. Но пока оно вот так.

Выводы

А их нету. Всё непрерывно ломается и чинится. Не используйте недокументированные функции. И имейте хотя бы один сервер под самой последней версией ОС, чтобы вовремя узнавать, что неизбежно сломается на других.

P.S. У нас есть задачи (проектная работа, удалёнка и т. д) для квалифицированных программистов на Python и JS. Мы - GrinDin.ru, компания по производству здорового питания премиального уровня. Если есть интерес, напишите на job@

P.P.S. Если это ещё кому-то мешает жить, вот патч.

Комментарии (2)


  1. UMBRON
    19.08.2024 12:10

    Спасибо)


  1. jackchickadee
    19.08.2024 12:10
    +1

    почему на сервере часы начали прыгать туда-сюда на 3 часа.

    пугаете.

    я подумал что проблемы с системными часами, с ntpd или сломали таймзону (как это было на винде 7 с обновлениями таймзон + реформами летнего времени в РФ).

    а у вас всего лишь какой-то овноскрипт на питоне сошел с ума.

    Выводы А их нету.

    их есть. они касаются питона и питон-программистов. писать не буду, не понравится слишком многим.