Я намагаюся розібрати канал 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 для відповіді № 1feedparser 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
ви правильно локалізуєте в 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)))
Django TIME_ZONE
установка насправді не має значення, тому що вона використовується тільки для цілей візуалізації або для автоматичного перетворення наївних даних.
Коли USE_TZ має значення True, це часовий пояс за промовчанням, який Django використовуватиме для відображення даних у шаблонах та інтерпретації даних, введених у форми.
Важливо завжди використовувати правильно локалізовані дати даних, незалежно від того, який часовий пояс використовується. Поки вони не в наївному форматі, їх буде правильно обробляти Django.