[英]Datetime localization with python/django
我正在嘗試解析RSS提要。 Feed中的條目包含以下日期元素:
<dc:date>2016-09-21T16:00:00+02:00</dc:date>
使用feedparser,我嘗試:
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設置不變,但要正確解析和存儲這個日期時間,而不會影響django時區設置?
編輯:也許這樣更清楚......
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
feedparser的entry.published_parsed
總是一個utc time 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在任何地方使用感知日期時間對象。 給定一個時區感知日期時間對象,無論你的TIME_ZONE
或timezone.get_current_timezone()
是什么,django都應該正確地將它保存到db。
您是否嘗試過使用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>)
使用
published_time = pytz.utc.localize(datetime.utcfromtimestamp(calendar.timegm(parsed_entry.published_parsed)))
Feedparser可以解析大量日期格式,您可以在此處找到它們。
正如您在feedparser/feedparser/datetimes/__init__.py
,Feedparser _parse_date
中的內置函數執行以下操作:
在GMT中將各種日期格式解析為9元組
這意味着在parsed_entry.published_parsed
您在GMT時區中有一個time.struct_time
對象。
使用時將其轉換為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
對象(我們知道它代表一個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正確處理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.