Python datetime.datetime от time.structtime разница

Я использую feedparser, чтобы получить записи из некоторых RSS-каналов. Записи имеют поле publ_parsed, которое анализирует feedparser в time.structtime.

Я использую эту функцию для преобразования time.structtime в datetime.datetime:

def publishParsedToDatetime(structTime): 
    return datetime.datetime.fromtimestamp(time.mktime(structTime))

Вход (structtime):

time.struct_time(tm_year=2015, tm_mon=8, tm_mday=1, tm_hour=20, tm_min=28, tm_sec=33, tm_wday=5, tm_yday=213, tm_isdst=0)

Выход (дата-время):

2015-08-01 21:28:33

Я вижу проблему, которая может быть связана с часовым поясом, разница между значениями structtime и datetime составляет 1 час.

Значение structtime - UTC. Но значение datetime.datetime не является ни UTC, ни моим текущим часовым поясом (CET, центральноевропейское время, мы наблюдаем летнее время, поэтому у нас сейчас UTC + 2 часа).

Как это можно объяснить?

2 ответа

Решение

На самом деле, как объяснено в документации дляdatetime.fromtimestampпо умолчанию конвертируется в местное время:

Возвращает локальную дату и время, соответствующие метке времени POSIX, например, возвращается time.time(). Если необязательный аргумент tz равен None или не указан, отметка времени преобразуется в локальные дату и время платформы, а возвращаемый объект datetime является наивным

Разница в 1 час может быть объяснена полемtm_isdst=0 говорит, что не использовать летнее время (несмотря на то, что вы используете местный часовой пояс).

Чтобы увидеть это более четко, мы построим два теста

import time, datetime

# this is how your time object was constructed before
tm_isdst = 0
t = time.mktime((2015, 8, 1, 20, 28, 33, 5, 213, tm_isdst))
print("Old conversion: {0}".format(datetime.datetime.fromtimestamp(t)))

# this is what happens if you let mktime "divine" a time zone
tm_isdst = -1
t = time.mktime((2015, 8, 1, 20, 28, 33, 5, 213, tm_isdst))
print("New conversion: {0}".format(datetime.datetime.fromtimestamp(t)))

Результат этого следующий:

Old conversion: 2015-08-01 21:28:33
New conversion: 2015-08-01 20:28:33

Проблема тогда, вы видите, в том, что structTime объект передается вашему publishParsedToDatetime имеет tm_isdst=0 но метка времени, которую вы хотели проанализировать, была для часового пояса DST.

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

calendar.timegm принимает в качестве входных данных временную шкалу UTC и возвращает свою временную метку. По сравнению, time.mktime принимает в качестве входных данных локальное время и возвращает его (UTC) метку времени. Все метки времени представляют секунды с начала эпохи 1970-1-1 00:00:00 UTC.

utcfromtimestamp принимает в качестве входных данных временную метку и преобразует ее в наивную (т.е. не зависящую от часового пояса) дату и время UTC. fromtimestamp берет ту же временную метку и преобразует ее в соответствующую наивную локальную дату и время.

Поскольку ваши расписания (например, structTime) являются UTC, вы должны использовать calendar.timegm не time.mktime, чтобы найти правильную метку времени. Как только у вас есть правильная метка времени, fromtimestamp вернет соответствующее наивное местное время.


import time
import calendar
import datetime as DT
timetuple = (2015, 8, 1, 20, 28, 33, 5, 213, 0)
timestamp = calendar.timegm(timetuple)    
naive_local_date = DT.datetime.fromtimestamp(timestamp)    
print('Naive local: {}'.format(naive_local_date))

доходность

Naive local: 2015-08-01 22:28:33
Другие вопросы по тегам