/ / Datetime локализация с python / django - python, django, datetime, feedparser

Локализиране на дата с Python / django - python, django, datetime, feedparser

Опитвам се да анализирам 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 за отговор № 1

feedparser "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 правилно локализирате в UTC datetime обект.

Пример:

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.