2011-12-08 13 views
13

का उपयोग किये बिना पायथन में एक तारीख को पार्स करना मैं किसी तीसरे पक्ष फ़ीड से प्राप्त होने वाली कुछ तिथियों को पार्स करने के लिए पायथन के dateutil.parser टूल का उपयोग कर रहा हूं। यह एक डिफ़ॉल्ट तिथि निर्दिष्ट करने की अनुमति देता है, जो आज के लिए डिफ़ॉल्ट रूप से चूक जाता है, पार्स किए गए दिनांक के गायब तत्वों को भरने के लिए। हालांकि यह सामान्य रूप से सहायक है, मेरे उपयोग के मामले में कोई सैन डिफ़ॉल्ट नहीं है, और मैं आंशिक तिथियों का इलाज करना पसंद करूंगा जैसे कि मुझे कोई तारीख नहीं मिली है (क्योंकि इसका लगभग हमेशा मतलब है कि मुझे डेटा खराब हो गया है)।डिफ़ॉल्ट

from dateutil import parser 
import datetime 

def parse_no_default(dt_str): 
    dt = parser.parse(dt_str, default=datetime.datetime(1900, 1, 1)).date() 
    dt2 = parser.parse(dt_str, default=datetime.datetime(1901, 2, 2)).date() 
    if dt == dt2: 
    return dt 
    else: 
    return None 

(। यह स्निपेट केवल, तारीख पर लग रहा है के रूप में है कि सभी मैं अपने आवेदन के लिए के बारे में परवाह है, लेकिन इसी तरह के तर्क समय घटक शामिल करने के लिए बढ़ाया जा सकता है)

: मैं चारों ओर निम्नलिखित काम लिखा है

मैं सोच रहा हूं (उम्मीद कर रहा हूं) ऐसा करने का एक बेहतर तरीका है। एक ही स्ट्रिंग को दो बार देखने के लिए यह देखने के लिए कि क्या यह अलग-अलग डिफॉल्ट में भरता है, कम से कम कहने के लिए संसाधनों की सकल बर्बादी की तरह लगता है।

यहाँ अपेक्षित व्यवहार के लिए परीक्षण (nosetest जनरेटर का उपयोग) के सेट है:

import nose.tools 
import lib.tools.date 

def check_parse_no_default(sample, expected): 
    actual = lib.tools.date.parse_no_default(sample) 
    nose.tools.eq_(actual, expected) 

def test_parse_no_default(): 
    cases = ( 
     ('2011-10-12', datetime.date(2011, 10, 12)), 
     ('2011-10', None), 
     ('2011', None), 
     ('10-12', None), 
     ('2011-10-12T11:45:30', datetime.date(2011, 10, 12)), 
     ('10-12 11:45', None), 
     ('', None), 
    ) 
    for sample, expected in cases: 
    yield check_parse_no_default, sample, expected 

उत्तर

8

आपके डोमेन के आधार पर निम्नलिखित समाधान काम कर सकते हैं:

DEFAULT_DATE = datetime.datetime(datetime.MINYEAR, 1, 1) 

def parse_no_default(dt_str):  
    dt = parser.parse(dt_str, default=DEFAULT_DATE).date() 
    if dt != DEFAULT_DATE: 
     return dt 
    else: 
     return None 

एक और दृष्टिकोण बंदर पैच पार्सर होगा कक्षा (यह बहुत हैकिस है, इसलिए यदि आपके पास अन्य विकल्प हैं तो मैं इसकी अनुशंसा नहीं करूंगा):

import dateutil.parser as parser 
def parse(self, timestr, default=None, 
      ignoretz=False, tzinfos=None, 
      **kwargs): 
    return self._parse(timestr, **kwargs) 
parser.parser.parse = parse 

इस प्रकार आप इसका इस्तेमाल कर सकते हैं:

>>> ddd = parser.parser().parse('2011-01-02', None) 
>>> ddd 
_result(year=2011, month=01, day=02) 
>>> ddd = parser.parser().parse('2011', None) 
>>> ddd 
_result(year=2011) 

जाँच जो सदस्यों परिणाम में उपलब्ध (DDD) करके आप यह समझ सकते हैं जब वापसी कोई नहीं। सभी क्षेत्रों उपलब्ध आप datetime वस्तु में ddd के कनवर्ट हो सकते हैं:

# ddd might have following fields: 
# "year", "month", "day", "weekday", 
# "hour", "minute", "second", "microsecond", 
# "tzname", "tzoffset" 
datetime.datetime(ddd.year, ddd.month, ddd.day) 
+0

जो केवल खाली स्ट्रिंग केस हल करता है। जब मेरे पास आंशिक तिथि होती है, तो यह अभी भी फ़ील्ड को निर्दिष्ट नहीं कर रहा है, लेकिन डिफॉल्ट की तुलना में एक अलग अंतिम तिथि प्राप्त करता है। मैंने आवश्यकताओं को चित्रित करने के लिए प्रश्न में कुछ यूनिट परीक्षण जोड़े हैं और यह उदाहरण कहां विफल रहता है। हालांकि एक नज़र डालने के लिए धन्यवाद! –

+1

स्पष्ट रूप से सावधान रहें, जाहिर है कि आपके पहले उदाहरण में आप डेटटाइम ऑब्जेक्ट के साथ डेट ऑब्जेक्ट की तुलना कर रहे हैं। यह हमेशा गैर बराबर होने जा रहा है। –

0

मैं dateutil साथ ठीक उसी समस्या में पड़ गए, मैं इस समारोह में लिखा था और मैं भावी पीढ़ी की खातिर इसे पोस्ट करेगा लगा। .day गुण है, जो मेरी जरूरतों के लिए काफी अच्छा था

from dateutil.parser import parser 
import datetime 
from StringIO import StringIO 

_CURRENT_YEAR = datetime.datetime.now().year 
def is_good_date(date): 
    try: 
     parsed_date = parser._parse(parser(), StringIO(date)) 
    except: 
     return None 
    if not parsed_date: return None 
    if not parsed_date.year: return None 
    if parsed_date.year < 1890 or parsed_date.year > _CURRENT_YEAR: return None 
    if not parsed_date.month: return None 
    if parsed_date.month < 1 or parsed_date.month > 12: return None 
    if not parsed_date.day: return None 
    if parsed_date.day < 1 or parsed_date.day > 31: return None 
    return parsed_date 

लौटे वस्तु एक datetime उदाहरण नहीं है, लेकिन यह .year, .month है, और,: मूल रूप से अंतर्निहित _parse पद्धति का उपयोग करके @ILYA Khlopotov पता चलता है की तरह। मुझे लगता है कि आप इसे आसानी से datetime उदाहरण में परिवर्तित कर सकते हैं।

0

सरल तिथि यह आपके लिए करता है (यह आंतरिक रूप से कई प्रारूपों को आजमाता है, लेकिन जितना आप सोच सकते हैं उतना नहीं, क्योंकि इसका उपयोग पैटर्न जो वैकल्पिक भागों के साथ पाइथन की तारीख पैटर्न का विस्तार करता है, जैसे regexps)।

https://github.com/andrewcooke/simple-date देखें - लेकिन केवल पायथन 3.2 और ऊपर (क्षमा करें)।

यह क्या आप डिफ़ॉल्ट रूप से चाहते हैं की तुलना में अधिक उदार है:

>>> for date in ('2011-10-12', '2011-10', '2011', '10-12', '2011-10-12T11:45:30', '10-12 11:45', ''): 
... print(date) 
... try: print(SimpleDate(date).naive.datetime) 
... except: print('nope') 
... 
2011-10-12 
2011-10-12 00:00:00 
2011-10 
2011-10-01 00:00:00 
2011 
2011-01-01 00:00:00 
10-12 
nope 
2011-10-12T11:45:30 
2011-10-12 11:45:30 
10-12 11:45 
nope 

nope 

लेकिन आप अपने खुद के प्रारूप निर्दिष्ट कर सकते हैं।उदाहरण के लिए:

>>> from simpledate import SimpleDateParser, invert 
>>> parser = SimpleDateParser(invert('Y-m-d(%T|)?(H:M(:S)?)?')) 
>>> for date in ('2011-10-12', '2011-10', '2011', '10-12', '2011-10-12T11:45:30', '10-12 11:45', ''): 
... print(date) 
... try: print(SimpleDate(date, date_parser=parser).naive.datetime) 
... except: print('nope') 
... 
2011-10-12 
2011-10-12 00:00:00 
2011-10 
nope 
2011 
nope 
10-12 
nope 
2011-10-12T11:45:30 
2011-10-12 11:45:30 
10-12 11:45 
nope 

nope 

ps invert() सिर्फ % की उपस्थिति जो अन्यथा एक असली गड़बड़ हो जाते हैं जब जटिल तारीख पैटर्न को निर्दिष्ट स्विच करता है। इसलिए यहाँ केवल शाब्दिक T चरित्र एक % उपसर्ग (मानक अजगर तारीख में स्वरूपण यह एक उपसर्ग के बिना केवल अल्फ़ा-न्यूमेरिक चरित्र होगा)

3

यह शायद एक "हैक" जरूरत है, लेकिन dateutil बहुत पर लगता है कि यह लग रहा है आपके द्वारा पास किए गए डिफ़ॉल्ट से कुछ विशेषताएं। आप एक 'नकली' डेटाटाइम प्रदान कर सकते हैं जो वांछित तरीके से विस्फोट करता है।

>>> import datetime 
>>> import dateutil.parser 
>>> class NoDefaultDate(object): 
...  def replace(self, **fields): 
...   if any(f not in fields for f in ('year', 'month', 'day')): 
...    return None 
...   return datetime.datetime(2000, 1, 1).replace(**fields) 
>>> def wrap_parse(v): 
...  _actual = dateutil.parser.parse(v, default=NoDefaultDate()) 
...  return _actual.date() if _actual is not None else None 
>>> cases = (
... ('2011-10-12', datetime.date(2011, 10, 12)), 
... ('2011-10', None), 
... ('2011', None), 
... ('10-12', None), 
... ('2011-10-12T11:45:30', datetime.date(2011, 10, 12)), 
... ('10-12 11:45', None), 
... ('', None), 
... ) 
>>> all(wrap_parse(test) == expected for test, expected in cases) 
True 
+0

अच्छा, साफ हैक भले ही यह एक हैक है! +1 – tzaman

+0

'प्रतिस्थापन' फ़ंक्शन के kwargs को पढ़ने के बाद भी मैं यह पता लगा सकता हूं कि पारित स्ट्रिंग में कौन से दिनांक तत्व निर्दिष्ट किए गए थे। केवल वर्ष, या वर्ष डब्ल्यू/माह इत्यादि। वास्तव में मुझे क्या चाहिए। – Winand

+0

यह अच्छा लग रहा था लेकिन वर्तमान में मेरे लिए काम नहीं किया। मैंने इस तरह के फ़ंक्शन को संशोधित किया और ऐसा लगता है कि यह ठीक है: 'def wrap_parse (v): कोशिश करें: _actual = ... विशेषता को छोड़कर त्रुटि: _actual = none' – user2205380

संबंधित मुद्दे