Python 3: временная метка к datetime: откуда этот дополнительный час? - PullRequest
7 голосов
/ 06 апреля 2010

Я использую следующие функции:

# The epoch used in the datetime API.
EPOCH = datetime.datetime.fromtimestamp(0)

def timedelta_to_seconds(delta):
    seconds = (delta.microseconds * 1e6) + delta.seconds + (delta.days * 86400)
    seconds = abs(seconds)

    return seconds

def datetime_to_timestamp(date, epoch=EPOCH):
    # Ensure we deal with `datetime`s.
    date = datetime.datetime.fromordinal(date.toordinal())
    epoch = datetime.datetime.fromordinal(epoch.toordinal())

    timedelta = date - epoch
    timestamp = timedelta_to_seconds(timedelta)

    return timestamp

def timestamp_to_datetime(timestamp, epoch=EPOCH):
    # Ensure we deal with a `datetime`.
    epoch = datetime.datetime.fromordinal(epoch.toordinal())

    epoch_difference = timedelta_to_seconds(epoch - EPOCH)
    adjusted_timestamp = timestamp - epoch_difference

    date = datetime.datetime.fromtimestamp(adjusted_timestamp)

    return date

И используя их с переданным кодом:

twenty = datetime.datetime(2010, 4, 4)

print(twenty)
print(datetime_to_timestamp(twenty))
print(timestamp_to_datetime(datetime_to_timestamp(twenty)))

И получаю следующие результаты:

2010-04-04 00:00:00
1270339200.0
2010-04-04 01:00:00

По какой-то причине я получаю дополнительный час, добавленный во время последнего вызова, несмотря на то, что мой код, насколько я вижу, не имеет недостатков.

Откуда этот дополнительный час?

Ответы [ 2 ]

4 голосов
/ 06 апреля 2010
# Ensure we deal with `datetime`s.
date = datetime.datetime.fromordinal(date.toordinal())

(Это полностью отрезает время суток, поскольку «порядковый» - это только число дня. Это то, что вы хотели сделать? Я подозреваю, что нет.)

В любом случае, как сказал Майкл, datetime.fromtimestamp дает вам наивное время, соответствующее тому, какое местное время для этой временной метки POSIX (UTC) будет для вас. Поэтому, когда вы звоните -

date = datetime.datetime.fromtimestamp(adjusted_timestamp)

вы получаете местное время для отметки времени POSIX, представляющей 2010-04-04T00: 00: 00, что, конечно, в BST на час вперед. Этого не происходит в обратном направлении, потому что ваша эпоха наступила в январе, когда BST не действует. (Однако ваш EPOCH также был бы полностью отключен, если бы вы не были в Великобритании.)

Вам следует заменить оба варианта использования datetime.fromtimestamp на datetime.utcfromtimestamp.

Печально, что datetime продолжает ужасную time традицию хранения времени по местному времени. Называть их «наивными» и убирать флаг DST только делает их еще хуже. Лично я не могу использовать datetime, предпочитая целые временные метки UTC для всего (преобразование в местные часовые пояса только для форматирования).

1 голос
/ 06 апреля 2010

Судя по вашему профилю, вы в Великобритании. Это означает, что вы в настоящее время используете UTC + 1 из-за перехода на летнее время.

Если я возьму вашу временную метку и проведу ее через datetime.fromtimestamp на Python 2.6 (я знаю, что вы используете Python 3, но это то, что у меня есть), это показывает мне, что она считает, что это относится к 2010-04-04 02: 00:00 - и я в CEST, так что это UTC + 2.

Запуск datetime.fromtimestamp (0), я получаю, что эпоха 1970-01-01 01:00:00. Затем это показывает мне, что он правильно добавляет только один час (поскольку 1 января за пределами летнего времени, а эпоха - это полночь UTC этой даты, здесь будет 01:00).

Другими словами, ваша проблема в том, что вы отправляете за время, к которому применен DST, но datetime_to_timestamp обрабатывает его так, как если бы DST не существовал. timestamp_to_datetime, однако, применяет DST.

К сожалению, я не знаю достаточно Python, чтобы знать, как вы решите это, но это должно, по крайней мере, дать вам кое-что для продолжения.

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