2015-12-14 5 views
5

के साथ डेटाटाइम स्थानीयकरण मैं एक आरएसएस फ़ीड पार्स करने की कोशिश कर रहा हूं। फ़ीड में प्रविष्टियों की तरह तारीख तत्व:पायथन/django

<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' 

... datatime सही UTC समय के रूप में संग्रहीत किया जाता है:

2016-09-21 14:00:00 

वहाँ Django सेटिंग्स रखने के लिए के रूप में वे कर रहे हैं, लेकिन पार्स और इस datetime ग स्टोर करने के लिए कोई तरीका है सही ढंग से, 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 
+1

क्या आप समय क्षेत्र रूपांतरण में रुचि रखते हैं या आप डेटाटाइम के साथ बस एक घंटा जोड़ने के लिए खुले रहेंगे।timedelta ऑपरेशन? – JwM

+0

आखिरकार, मैं यूटीसी में सही समय लेना चाहता हूं। अब एक घंटा दूर लेना (दिन की बचत अवधि में दो घंटे) जाने का एक तरीका हो सकता है। मैंने अभी तक इसे नहीं देखा है। मैं सोच रहा था कि क्या कोई और तरीका था। मैंने उदाहरण के लिए timzone.activate() और timezone.deactivate() की कोशिश की जो कि वर्तमान_टाइज़ोन को सही तरीके से बदलना प्रतीत होता था, लेकिन इससे समस्या ठीक नहीं हुई। – apiljic

+0

आप समय-समय पर जागरूक कर सकते हैं, या टाइमज़ोन बदल सकते हैं यदि यह पहले से ही जागरूक है लेकिन गलत है। –

उत्तर

2

फीडपार्सर entry.published_parsed हमेशा एक यूटीसी समय ट्यूपल होता है जो इनपुट समय स्ट्रिंग होता है।

from datetime import datetime 

utc_time = datetime(*entry.published_parsed[:6], tzinfo=utc) 

जहां utc एक tzinfo वस्तु जैसे datetime.timezone.utc, pytz.utc, या बस अपने custom tzinfo (for older python versions) है: समय क्षेत्र अवगत datetime वस्तु प्राप्त करने के लिए।

आपको स्थानीय समय की अपेक्षा रखने वाले mktime() पर यूटीसी समय नहीं पारित करना चाहिए। वही त्रुटि: Have a correct datetime with correct timezone

सुनिश्चित करें कि USE_TZ=True ताकि django हर जगह जागरूक डेटाटाइम ऑब्जेक्ट्स का उपयोग करे। एक टाइमज़ोन-जागरूक डेटाटाइम ऑब्जेक्ट को देखते हुए, django को इसे 0bजो कुछ भी सही ढंग से डीबी में सहेजना चाहिए।

+0

मैंने इस समाधान की भी कोशिश की। यह भी काम करता है। धन्यवाद! – apiljic

1

आप datetime.utcfromtimestamp() बजाय datetime.fromtimestamp() उपयोग करने की कोशिश की है?

एक माध्यमिक समाधान के रूप में, आप अन-पार्स डेटा प्राप्त कर सकते हैं (मेरा मानना ​​है कि यह entry.published के रूप में उपलब्ध है?) और सिर्फ अजगर-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>) 
+0

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 13:00 : 00 2016-09-21 13: 00: 00 + 00: 00 ... यह utcfromtimestamp() का आउटपुट है। टाइमज़ोन बदल गया है, लेकिन समय अभी भी सही नहीं है। – apiljic

+0

दूसरा समाधान काम कर सकता है। मेरी एकमात्र चिंता यह है कि कई अलग-अलग दिनांक प्रारूप हैं। अब तक जो हमने सामना किया है, उससे फीडपार्सर में से किसी के साथ कोई समस्या नहीं थी। मैं सोच रहा हूं कि आपके द्वारा सुझाए गए पार्सर समान रूप से अच्छी तरह से काम करते हैं। क्या आप इसे कई अलग-अलग दिनांक प्रारूपों के लिए उपयोग करते हैं? – apiljic

+1

@apiljic: इनपुट टाइम स्ट्रिंग्स ('_parsed' विशेषताएँ) को पार्स करने के लिए फीडपार्सर का उपयोग करें। 'dateutil 'बहुत अधिक इनपुट समय स्वरूप स्वीकार करता है और इसलिए चुपचाप गलत परिणाम लौटा सकता है। – jfs

1

उपयोग

published_time = pytz.utc.localize(datetime.utcfromtimestamp(calendar.timegm(parsed_entry.published_parsed))) 

Feedparser दिनांक प्रारूपों की एक बड़ी रेंज पार्स कर सकते हैं, तो आप उन्हें here पा सकते हैं।

Parses a variety of date formats into a 9-tuple in GMT

इसका मतलब है कि parsed_entry.published_parsed में आप GMT समय क्षेत्र में एक time.struct_time वस्तु है:

आप feedparser/feedparser/datetimes/__init__.py में देख सकते हैं, Feedparser _parse_date से निर्मित समारोह निम्नलिखित है।

जब आप इसे एक datetime वस्तु में बदलने का

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

समस्या mktime मानता है कि कि पारित कर दिया टपल स्थानीय समय है, जो नहीं है में है, यह GMT/UTC का उपयोग कर! इसके अलावा आप रूपांतरण के अंत में datetime ऑब्जेक्ट को सही ढंग से स्थानांतरित नहीं करते हैं।

आपको उस रूपांतरण को निम्नलिखित के साथ प्रतिस्थापित करने की आवश्यकता है, यह याद रखना कि फीडपार्सर जीएमटी struct_time देता है, और उस समय को स्थानीयकृत करें जिसे आप पसंद करते हैं (सादगी के लिए यूटीसी)।

  • आप calendar.timegm, जो युग और तारीख एक पैरामीटर के रूप में पारित के बीच सेकंड की संख्या देता है, यह सोचते हैं कि पारित कर दिया वस्तु यूटीसी में है का उपयोग/GMT (हम जानते हैं Feedparser से है)
  • आप utcfromtimestamp का उपयोग एक बेवकूफ datetime ऑब्जेक्ट प्राप्त करने के लिए (जिसे हम जानते हैं कि यूटीसी में डेटाटाइम का प्रतिनिधित्व करता है, लेकिन पाइथन इस पल में नहीं है)
  • pytz.utc.localize के साथ आप यूटीसी 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 का उपयोग करते हैं तो आपको पायथन को बताना होगा कि आपके द्वारा बनाए गए datetime ऑब्जेक्ट में स्थानीय टाइमज़ोन है। मान आप यूरोप/बर्लिन में कर रहे हैं, यह भी ठीक है:

pytz.timezone('Europe/Berlin').localize(datetime.fromtimestamp(calendar.timegm(parsed_entry.published_parsed))) 

थे parsed_entry.published_parsed भी स्थानीय समय क्षेत्र में, mktimecalendar.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 सेटिंग वास्तव में नहीं है मामला, क्योंकि यह केवल विज़ुअलाइजेशन उद्देश्यों के लिए या स्वचालित रूप से बेवकूफ डेटाटाइम को परिवर्तित करने के लिए उपयोग किया जाता है।

When USE_TZ is True, this is the default time zone that Django will use to display datetimes in templates and to interpret datetimes entered in forms.

हमेशा उचित स्थानीयकृत डेटाटाइम का उपयोग करना महत्वपूर्ण है, इससे कोई फर्क नहीं पड़ता कि किस समय क्षेत्र का उपयोग किया जाता है। जब तक वे निष्पक्ष प्रारूप में नहीं हैं, तब तक उन्हें Django द्वारा ठीक से संभाला जाएगा।

+0

यह अनावश्यक जटिल है। यहां एक [सरल समाधान] है (http://stackoverflow.com/a/34292796/4279) – jfs

+0

मैं मानता हूं, आपको इस जटिलता की आवश्यकता होती है जब आपको डीएसटी ध्वज पर विचार करने की आवश्यकता होती है, जो कि स्थानीय समय का मामला है (वह जगह है आप mktime का उपयोग करते हैं) और यूटीसी के लिए नहीं, जो यह नहीं है। –

+0

यदि समय यूटीसी नहीं है तो कोड केवल जटिल नहीं है; यह सिर्फ गलत है। – jfs