Python does not specify a date string handling class

  • 2020-04-02 13:42:53
  • OfStack

I analyzed the features of time format such as 19920203, 199203, 1992.02.03, 1992.02, 1992-02-03, 1992-02, 920203, and listed the regular expressions as follows:


^((?:19|20)?d{2})[-.]?((?:[0-1]?|1)[0-9])[-.]?((?:[0-3]?|[1-3])[0-9])?$

Of course, this expression is not perfect, it can only do simple cutting, can't judge the validity of the date, about whether the date is legal, I still leave Python time function to deal with it.

According to the above regular expression, the DateParser class I wrote is as follows:


import re
import datetime

# ***************************************************
# *
# * Description:  Non-standard date string handling 
# * Author: wangye  <pcn88 at hotmail dot com>
# *
# ***************************************************
class DateParser(object):

    def __init__(self):
        self.pattern = re.compile(
        r'^((?:19|20)?d{2})[-.]?((?:[0-1]?|1)[0-9])[-.]?((?:[0-3]?|[1-3])[0-9])?$'
        )

    def __cutDate(self, date, flags):
        y = date.year
        m = date.month if flags[1] else 1
        d = date.day if flags[2] else 1
        return datetime.date(y, m, d)

    def __mergeFlags(self, flags1, flags2):
        l = []
        length = min(len(flags1), len(flags2))
        for i in range(0, length):
            if flags1[i] and flags2[i]:
                l.append(True)
            else:
                l.append(False)
        return l

    def parse(self, strdate):
        """
         Description: time resolution method. 
         Parameters: strdate  The time string to analyze, such as the target time type datetime(1992, 2, 3)
               One of the following strings can be parsed: 
            19920203 
            199203
            1992.02.03
            1992.02
            1992-02-03
            1992-02
            920203
         The return value: 
             If successful 
             tuples (datetime, flags) , including datetime Represents the legal time of completion of the transformation, 
        flags It's the flag bit, it's the significant bit, for example 199202 Actually converted year and month, day not, 
         But this function returns by default 1 Day, but flags Will be represented as (True, True, False),
         The previous two True The year and the month are converted, respectively, and the last one False The date is not converted. 
             If it fails 
             return None . 
        """
        m = self.pattern.match(strdate)
        flags = [False, False, False]
        if m:
            matches = list(m.groups())
            flags = list(map(lambda x:True if x!=None else False, matches))
            results = list(map(lambda x:int(x) if x!=None else 1, matches))
            # results = list(map(lambda x:1 if x==None else x, results))
            if results[0]<100:
                if results[0]>9:
                    results[0] += 1900
                else:
                    results[0] += 2000

            return (datetime.date(results[0], results[1], results[2]), flags)
        else:
            return None

    def convert(self, strdate, format):
        """
         Description: convert date to specified format. 
         Parameters: strdate  with parse methods strdate Parameters. 
              format Python Time format identification, same datetime.date.strftime Format the identity. 
         The return value: 
             If successful, returns the specified format Format of the time string. 
             If it fails, return None . 
        """
        date = self.parse(strdate)
        if date:
            date = date[0]
            return datetime.date.strftime(date, format)
        else:
            return None

    def compare(self, strdate1, strdate2):
        """
         Description: compare two dates. 
         Parameters: strdate1  and  strdate2  with parse methods strdate parameter 
         The return value: 
             It could be one of the following values 
            -4  strdate1  invalid ,  strdate2  effective 
            -3  strdate1  effective ,  strdate2  invalid 
            -2  strdate1  and  strdate2  invalid 
            -1  strdate1 < strdate2
             0  strdate1 = strdate2
             1  strdate1 > strdate2
        """
        date1,flags1 = self.parse(strdate1)
        date2,flags2 = self.parse(strdate2)

        if date1 == None and date2 != None:
            return -4
        if date1 != None and date2 == None:
            return -3
        elif date1 == None and date2 == None:
            return -2

        flags = self.__mergeFlags(flags1, flags2)
        date1 = self.__cutDate(date1, flags)
        date2 = self.__cutDate(date2, flags)

        if date1>date2:
            return 1
        elif date1<date2:
            return -1
        else:
            return 0

Here are some examples for your reference:


>>> DateParser().parse("19860126")
(datetime.date(1986, 1, 26), [True, True, True])
>>> DateParser().parse("199111")
(datetime.date(1991, 11, 1), [True, True, False])
>>> DateParser().parse("1991")
(datetime.date(1919, 9, 1), [True, True, True])
>>> DateParser().parse("8511")
(datetime.date(1985, 11, 1), [True, True, False])
>>> DateParser().convert("19911101", "%Y * %m * %d")
'1991 * 11 * 01'
>>> DateParser().convert("1990.1.01", "%Y.%m.%d")
'1990.01.01'
>>> DateParser().compare("1992.2", "19922")
0
>>> DateParser().compare("1992.2", "1956.03.1")
1


Related articles: