Сбой Python в Windows с датой и временем, близким к эпохе - PullRequest
2 голосов
/ 08 июля 2019

Python 3.7 в Windows 10:

>>> from datetime import datetime
>>> datetime.fromtimestamp(0)
datetime.datetime(1970, 1, 1, 0, 0)
>>> datetime.fromtimestamp(0).timestamp()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argument
>>> datetime.fromtimestamp(3600 * 3).timestamp()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argument
>>> datetime.fromtimestamp(360000).timestamp()
360000.0

Я понимаю, что в Windows диапазон временных отметок ограничен 1970 - 2038 гг. Из-за размера 32-разрядного целого числа. Но действительно странно, что он падает на отметке времени, которая все еще должна быть разрешена. FWIW, я в UTC + 2, поэтому, если есть какая-то проблема с часовым поясом, я ожидал, что отметка времени 3600 * 3 (3 часа) сработает. Могу ли я как-то заставить это работать или я должен просто признать, что очень низкие временные метки не будут работать?

1 Ответ

2 голосов
/ 08 июля 2019

Хорошо, я немного покопался в исходном коде Python. Проблема заключается в функции _PyTime_localtime. Это вызывает функцию localtime_s , которая принимает 2 аргумента time_t t и struct tm *tm. Где t - это time_t объект для преобразования и tm результирующая временная структура. Когда вы передаете 0 как time_t, что совершенно правильно, результирующая структура имеет поле tm_hour, установленное в 1 на моем компьютере. Также есть другой код для не-Windows вариантов, который вместо этого вызывает localtime_r .

Теперь проблема перемещается во внутреннюю функцию utc_to_seconds, которая принимает временную структуру (разбитую на аргументы, например: int year, int month, int day, int hour, int minute, int second). Теперь для года, месяца и дня проблем нет, он преобразуется в порядковый номер (который, кстати, является правильным порядковым числом). Но тогда функция имеет следующую последнюю строку:

return ((ordinal * 24 + hour) * 60 + minute) * 60 + second;

Где EPOCH должен вернуть туда 62135683200, но из-за этого дополнительного часа мы получаем 62135686800.

Все это объединяется во внутренней функции local_to_seconds

long long t, a, b, u1, u2, t1, t2, lt;
t = utc_to_seconds(year, month, day, hour, minute, second);
/* Our goal is to solve t = local(u) for u. */
lt = local(t);
if (lt == -1)
    return -1;
a = lt - t;
u1 = t - a;
t1 = local(u1);

Где t = 62135683200 и lt = 62135686800. В итоге мы получим u1 = -3600, что приведет к неверному параметру.

Итак, сделайте вывод: проблема в том, когда вы звоните timestamp. Я не совсем уверен, каким будет решение, чтобы исправить это в C-коде, но это определенно похоже на ошибку, я думаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...