/ / Локалізація datetime з python / django - python, django, datetime, feedparser

Локалізація Datetime за допомогою python / django - python, django, datetime, feeds

Я намагаюся розібрати канал RSS. Записи у каналі мають елементи дати:

<dc:date>2016-09-21T16:00:00+02:00</dc:date>

Використовуючи компілятор, я намагаюся зробити:

published_time = datetime.fromtimestamp(mktime(entry.published_parsed))

Але проблема в тому, що я, здається, отримую неправильний час, що зберігається в базі даних. У цьому конкретному випадку дата-час зберігається як:

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?

EDIT: Можливо, це ясніше ...

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 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).

Ви не повинні переходити час utc mktime() що очікує місцевий час. Одна й та ж помилка: Здійснюйте правильний час даних з правильним часовим поясом.

Переконайтеся USE_TZ=True так що django всюди використовує об'єкти даного часу. Враховуючи об'єкт дату-час, відомий тимчасовим поясом, 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)))

Django TIME_ZONE установка насправді не має значення, тому що вона використовується тільки для цілей візуалізації або для автоматичного перетворення наївних даних.

Коли USE_TZ має значення True, це часовий пояс за промовчанням, який Django використовуватиме для відображення даних у шаблонах та інтерпретації даних, введених у форми.

Важливо завжди використовувати правильно локалізовані дати даних, незалежно від того, який часовий пояс використовується. Поки вони не в наївному форматі, їх буде правильно обробляти Django.