Опитвам се да анализирам RSS емисия. Записите в емисията имат елементи от датата като:
<dc:date>2016-09-21T16:00:00+02:00</dc:date>
С помощта на хартиен носител се опитвам да направя:
published_time = datetime.fromtimestamp(mktime(entry.published_parsed))
Но проблемът е, че изглежда, че получавам погрешно време в базата данни. В този конкретен случай datetime се съхранява като:
2016-09-21 13:00:00
... когато очаквам 14:00 - правилното UTC време.
Предполагам, че проблемът е в настройките на django, където имаме:
TIME_ZONE = "Europe/Berlin"
Защото, когато преминавам на:
TIME_ZONE = "UTC"
... времето за данни се съхранява като правилно UTC време:
2016-09-21 14:00:00
Има ли някакъв начин да се запазят настройките на django както са те, но да се анализира и съхранява правилно този datetime, без настройката на django timezone да го засегне?
РЕДАКТИРАНЕ: Може би е по-ясно като това ...
print entry.published_parsed
published_time = datetime.fromtimestamp(mktime(entry.published_parsed))
print published_time
localized_time = pytz.timezone(settings.TIME_ZONE).localize(published_time, is_dst=None)
print localized_time
time.struct_time(tm_year=2016, tm_mon=9, tm_mday=21, tm_hour=14, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=265, tm_isdst=0)
2016-09-21 15:00:00
2016-09-21 15:00:00+02:00
Отговори:
2 за отговор № 1feedparser "S entry.published_parsed
е винаги utc време tuple каквото и да е въведен времеви низ. За да се запознаете с часовата зона datetime
предмет:
from datetime import datetime
utc_time = datetime(*entry.published_parsed[:6], tzinfo=utc)
където utc
е обект tzinfo, като например datetime.timezone.utc
, pytz.utc
, или просто вашия персонализирана tzinfo (за по-стари версии на python).
Не трябва да прехвърляте времето на mktime()
което очаква местно време. Същата грешка: Имате правилно датиране с точно време.
Уверете се USE_TZ=True
така, че джанго използва познати обекти от датата, навсякъде. Като се има предвид часовият обект с дата и час, django трябва да го запише на db правилно независимо от вашето TIME_ZONE
или timezone.get_current_timezone()
сте.
1 за отговор № 2
Опитвали ли сте да използвате datetime.utcfromtimestamp()
вместо datetime.fromtimestamp()
?
Като второстепенно решение можете да получите непроверени данни (смятам, че са достъпни като entry.published
?) и просто използвайте python-dateutil за синтактичен анализ на низ, след което го конвертирайте pytz.utc
такава зона.
>>> import pytz
>>> from dateutil import parser
>>> dt = parser.parse("2016-09-21T16:00:00+02:00")
>>> dt
datetime.datetime(2016, 9, 21, 16, 0, tzinfo=tzoffset(None, 7200))
>>> dt.astimezone(pytz.utc)
datetime.datetime(2016, 9, 21, 14, 0, tzinfo=<UTC>)
1 за отговор № 3
употреба
published_time = pytz.utc.localize(datetime.utcfromtimestamp(calendar.timegm(parsed_entry.published_parsed)))
Feedparser може да анализира голям диапазон от формати за дата, можете да ги намерите тук.
Както можете да видите feedparser/feedparser/datetimes/__init__.py
, вградената функция от Feedparser _parse_date
прави следното:
Разбива различни формати за дата в 9-тота в GMT
Това означава, че в parsed_entry.published_parsed
имате time.struct_time
обект в GMT часовия пояс.
Когато го конвертирате в a datetime
използване на обект
published_time = datetime.fromtimestamp(mktime(parsed_entry.published_parsed))
проблемът е такъв mktime
приема, че преминалият кортеж е в местно време, което не е, то е GMT / UTC datetime
обект в края на преобразуването.
Трябва да замените това преобразуване със следното, като помните, че Feedparser връща GMT struct_time
и локализирайте това с часовата зона, която ви харесва (UTC в името на простотата).
- Ти използваш
calendar.timegm
, който показва броя на секундите между епохата и датата, подадена като параметър, ако приемем, че преминалият обект е в UTC / GMT (знаем от Feedparser, че е) - Ти използваш
utcfromtimestamp
да се получи наивноdatetime
обект (който знаем, че представлява datetime в UTC, но в момента Python не го прави) - с
pytz.utc.localize
правилно локализирате в UTCdatetime
обект.
Пример:
import calendar
from datetime import datetime
import pytz
localized_dt = pytz.utc.localize(datetime.utcfromtimestamp(calendar.timegm(parsed_entry.published_parsed)))
Докато сте последователни, няма значение дали използвате fromtimestamp
или utcfromtimestamp
, Ако използвате fromtimestamp
трябва да кажете на Python, че datetime
обектът, който сте създали, има местната часова зона. Да предположим, че сте в Европа / Берлин, това също е добре:
pytz.timezone("Europe/Berlin").localize(datetime.fromtimestamp(calendar.timegm(parsed_entry.published_parsed)))
Са били parsed_entry.published_parsed
също в местна часова зона, mktime
трябва да се използва вместо calendar.timegm
.
Като алтернатива можете да анализирате сами данните, които получавате от Feedparser parsed_entry["published"]
from dateutil import parser
localized_dt = parser.parse(parsed_entry["published"])
Можете да проверите дали се връща следното True
:
parser.parse(parsed_entry["published"]) == pytz.utc.localize(datetime.utcfromtimestamp(calendar.timegm(parsed_entry.published_parsed)))
Джанго TIME_ZONE
настройката всъщност не е от значение, защото се използва само за целите на визуализацията или за автоматично преобразуване на наивни дати.
Когато USE_TZ е True, това е часовата зона по подразбиране, която Django ще използва за показване на дати в шаблони и за интерпретиране на въведените във формуляри дати.
Важно е винаги да се използват правилно локализирани дати, без значение коя часова зона се използва. Докато не са в наивен формат, те ще бъдат правилно обработени от Django.