पायथन में -0400 टाइमज़ोन स्ट्रिंग के साथ दिनांक पार्स कैसे करें?


81

मेरे पास '2009/05/13 19:19:30 -0400' फॉर्म की एक तारीख स्ट्रिंग है। ऐसा लगता है कि पायथन के पिछले संस्करणों ने अनुगामी टाइमज़ोन विनिर्देशन के लिए स्टेपटाइम में% z प्रारूप टैग का समर्थन किया होगा, लेकिन लगता है कि 2.6.x ने इसे हटा दिया है।

इस स्ट्रिंग को डेटाइम ऑब्जेक्ट में पार्स करने का सही तरीका क्या है?

जवाबों:


117

आप खजूर से पार्स फ़ंक्शन का उपयोग कर सकते हैं:

>>> from dateutil.parser import parse
>>> d = parse('2009/05/13 19:19:30 -0400')
>>> d
datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=tzoffset(None, -14400))

इस तरह आप एक डेटाटाइम ऑब्जेक्ट प्राप्त करते हैं जिसे आप तब उपयोग कर सकते हैं।

जैसा कि उत्तर दिया गया है , dateutil2.0 पायथन 3.0 के लिए लिखा गया है और यह पायथन 2.x के साथ काम नहीं करता है। पायथन के लिए 2.x dateutil1.5 का उपयोग करने की आवश्यकता है।


13
यह मेरे लिए ( dateutil2.1) पायथन के साथ ठीक काम करता है 2.7.2; अजगर 3 की आवश्यकता नहीं है। ध्यान दें कि यदि आप पाइप से स्थापित कर रहे हैं, तो पैकेज का नाम है python-dateutil
BigglesZX

47

%z पायथन 3.2+ में समर्थित है:

>>> from datetime import datetime
>>> datetime.strptime('2009/05/13 19:19:30 -0400', '%Y/%m/%d %H:%M:%S %z')
datetime.datetime(2009, 5, 13, 19, 19, 30,
                  tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))

पिछले संस्करणों पर:

from datetime import datetime

date_str = '2009/05/13 19:19:30 -0400'
naive_date_str, _, offset_str = date_str.rpartition(' ')
naive_dt = datetime.strptime(naive_date_str, '%Y/%m/%d %H:%M:%S')
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
   offset = -offset
dt = naive_dt.replace(tzinfo=FixedOffset(offset))
print(repr(dt))
# -> datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=FixedOffset(-240))
print(dt)
# -> 2009-05-13 19:19:30-04:00

डॉक्स से कोड उदाहरण केFixedOffset आधार पर एक वर्ग कहां है :

from datetime import timedelta, tzinfo

class FixedOffset(tzinfo):
    """Fixed offset in minutes: `time = utc_time + utc_offset`."""
    def __init__(self, offset):
        self.__offset = timedelta(minutes=offset)
        hours, minutes = divmod(offset, 60)
        #NOTE: the last part is to remind about deprecated POSIX GMT+h timezones
        #  that have the opposite sign in the name;
        #  the corresponding numeric value is not used e.g., no minutes
        self.__name = '<%+03d%02d>%+d' % (hours, minutes, -hours)
    def utcoffset(self, dt=None):
        return self.__offset
    def tzname(self, dt=None):
        return self.__name
    def dst(self, dt=None):
        return timedelta(0)
    def __repr__(self):
        return 'FixedOffset(%d)' % (self.utcoffset().total_seconds() / 60)

1
यह ValueError: 'z' is a bad directive in format '%Y-%m-%d %M:%H:%S.%f %z'मेरे मामले में एक कारण बनता है (पायथन 2.7)।
जोनाथन एच

@ चेल्होन यह पायथन 2.7 पर काम करने वाला नहीं है। जवाब के शीर्ष पर देखो।
jfs

अजीब, वैसे, यह पायथन 2.7 डॉक्स पर उल्लिखित सभी पर नहीं है : डॉक्सहोमथोन.org
62mkv

22

यहाँ "%z"पायथन 2.7 और उससे पहले के मुद्दे को ठीक किया गया है

के बजाय का उपयोग करने का:

datetime.strptime(t,'%Y-%m-%dT%H:%M %z')

timedeltaइस तरह, समय क्षेत्र के लिए खाते का उपयोग करें:

from datetime import datetime,timedelta
def dt_parse(t):
    ret = datetime.strptime(t[0:16],'%Y-%m-%dT%H:%M')
    if t[18]=='+':
        ret-=timedelta(hours=int(t[19:22]),minutes=int(t[23:]))
    elif t[18]=='-':
        ret+=timedelta(hours=int(t[19:22]),minutes=int(t[23:]))
    return ret

ध्यान दें कि तिथियों को परिवर्तित किया जाएगा GMT, जो समय क्षेत्र की चिंता किए बिना तिथि अंकगणित करने की अनुमति देगा।


मुझे यह पसंद है, हालांकि आपको 'सेकंड =' को 'मिनट =' में बदलने की आवश्यकता है।
डेव

1
एक नोट के रूप में, यदि आप एक स्ट्रिंग में एक टाइमज़ोन लेना चाहते थे, और डेटाइम को यूटीसी में परिवर्तित करते हैं, तो आप यहां सूचीबद्ध विपरीत तर्क का उपयोग करेंगे। यदि टाइमज़ोन में ए + है, तो आप टाइमडेल्टा को घटाते हैं, और इसके विपरीत।
सेक्टर 95

यूटीसी के लिए परिवर्तन, गलत था अगर वहाँ एक है +चरित्र timedelta किया जाना चाहिए substracted , और उपाध्यक्ष प्रतिकूल। मैंने कोड को संपादित और ठीक किया है।
टोमैटोस्टिक

7

Dateutil का उपयोग करने में समस्या यह है कि आपके पास क्रमांकन और deserialization दोनों के लिए समान प्रारूप स्ट्रिंग नहीं हो सकता है, क्योंकि dateutil में सीमित स्वरूपण विकल्प (केवल dayfirstऔर केवल yearfirst) हैं।

अपने आवेदन में, मैं। स्ट्रिंग फ़ाइल में प्रारूप स्ट्रिंग संग्रहीत करता हूं, और प्रत्येक परिनियोजन का अपना प्रारूप हो सकता है। इस प्रकार, मुझे वास्तव में डेटुटिल दृष्टिकोण पसंद नहीं है।

यहाँ एक वैकल्पिक विधि है जो इसके बजाय pytz का उपयोग करती है:

from datetime import datetime, timedelta

from pytz import timezone, utc
from pytz.tzinfo import StaticTzInfo

class OffsetTime(StaticTzInfo):
    def __init__(self, offset):
        """A dumb timezone based on offset such as +0530, -0600, etc.
        """
        hours = int(offset[:3])
        minutes = int(offset[0] + offset[3:])
        self._utcoffset = timedelta(hours=hours, minutes=minutes)

def load_datetime(value, format):
    if format.endswith('%z'):
        format = format[:-2]
        offset = value[-5:]
        value = value[:-5]
        return OffsetTime(offset).localize(datetime.strptime(value, format))

    return datetime.strptime(value, format)

def dump_datetime(value, format):
    return value.strftime(format)

value = '2009/05/13 19:19:30 -0400'
format = '%Y/%m/%d %H:%M:%S %z'

assert dump_datetime(load_datetime(value, format), format) == value
assert datetime(2009, 5, 13, 23, 19, 30, tzinfo=utc) \
    .astimezone(timezone('US/Eastern')) == load_datetime(value, format)

2

पुराने पायथन के लिए एक लाइनर वहाँ से बाहर। आप समय-सारणी को 1 / -1 से गुणा कर सकते हैं जो कि +/- साइन पर निर्भर करता है, जैसे:

datetime.strptime(s[:19], '%Y-%m-%dT%H:%M:%S') + timedelta(hours=int(s[20:22]), minutes=int(s[23:])) * (-1 if s[19] == '+' else 1)

-10

यदि आप लिनक्स पर हैं, तो आप बाह्य dateकमांड का उपयोग dwim करने के लिए कर सकते हैं :

import commands, datetime

def parsedate(text):
  output=commands.getoutput('date -d "%s" +%%s' % text )
  try:
      stamp=eval(output)
  except:
      print output
      raise
  return datetime.datetime.frometimestamp(stamp)

यह निश्चित रूप से डेट्यूटिल से कम पोर्टेबल है, लेकिन थोड़ा अधिक लचीला है, क्योंकि dateयह "कल" ​​या "पिछले साल" जैसे इनपुट को भी स्वीकार करेगा :-)


3
मुझे नहीं लगता कि इसके लिए किसी बाहरी प्रोग्राम को कॉल करना अच्छा है। और अगला कमजोर बिंदु: eval (): यदि आप अब एक वेबसर्वर इस कोड को निष्पादित करते हैं, तो आप सर्वर पर मनमाना कोड निष्पादन कर सकते हैं!
गुएतली

5
यह सब इस संदर्भ पर निर्भर करता है: यदि हम जो कुछ भी कर रहे हैं, वह केवल एक लिखने-और-फेंक-दूर की स्क्रिप्ट है, तो ये कमजोरियां सिर्फ अप्रासंगिक हैं :-)
गयूम

10
डाउन-वोटिंग इस कारण: 1) यह कुछ तुच्छ के लिए एक सिस्टम कॉल करता है, 2) यह सीधे तार को एक शेल कॉल में इंजेक्ट करता है, 3) यह eval कहता है (), और 4) इसका एक अपवाद कैच-ऑल है। मूल रूप से यह एक उदाहरण है कि चीजों को कैसे नहीं करना है।
बेंज

इस मामले में, हालांकि eval बुराई है और इसका उपयोग नहीं किया जाना चाहिए। एक बाह्य कॉल टाइमज़ोन अवगत डेटास्ट्रिंग से यूनिक्स टाइमस्टैम्प प्राप्त करने का सबसे आसान और सबसे व्यावहारिक तरीका लगता है, जहां टाइमज़ोन एक संख्यात्मक ऑफसेट नहीं है।
लेलियल

1
खैर, फिर से, यह "बुराई बुराई है" आदर्श वाक्य वास्तव में आपके संदर्भ (जो ओपी द्वारा नहीं कहा गया था) पर निर्भर करता है। जब मैं अपने स्वयं के उपयोग के लिए स्क्रिप्ट लिखता हूं, तो मैं उदारतापूर्वक eval का उपयोग करता हूं, और यह भयानक है। पायथॉन गोंद लिपियों के लिए एक महान भाषा है! बेशक आप ऊपर दिए गए कुछ जवाबों की तरह जटिल सामान्य-केस ओवर-इंजीनियर समाधानों को रोल कर सकते हैं, और फिर दावा कर सकते हैं कि यह केवल-द-द-वे-टू-इट, अला जावा है। लेकिन कई उपयोग-मामलों के लिए एक त्वरित और गंदा समाधान उतना ही अच्छा है।
गोमो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.