Commits

Brandon Nielsen committed 0f9612d

Added pair of 'general' functions for dates and times.

Comments (0)

Files changed (2)

aniso8601/__init__.py

 
 import datetime
 
+def parse_date(isodatestr):
+    #Given a string in any ISO8601 date format, return a datetime.date
+    #object that corresponds to the given date. Valid string formats are:
+    #
+    #Y[YYY]
+    #YYYY-MM-DD
+    #YYYYMMDD
+    #YYYY-MM
+    #YYYY-Www
+    #YYYYWww
+    #YYYY-Www-D
+    #YYYYWwwD
+    #YYYY-DDD
+    #YYYYDDD
+    #
+    #Note that the ISO8601 date format of ±YYYYY is expressly not supported
+
+    if isodatestr.startswith('+') or isodatestr.startswith('-'):
+        raise NotImplementedError('ISO8601 extended year representation not supported.')
+
+    if isodatestr.find('W') != -1:
+        #Handle ISO8601 week date format
+        return parse_week_date(isodatestr)
+
+    #If the size of the string of 4 or less, assume its a truncated year representation
+    if len(isodatestr) <= 4:
+        return parse_year(isodatestr)
+
+    datestrsplit = isodatestr.split('-')
+
+    #An ISO string may be a calendar represntation if:
+    # 1) When split on a hyphen, the sizes of the parts are 4, 2, 2 or 4, 2
+    # 2) There are no hyphens, and the length is 8
+
+    #Check case 1
+    if len(datestrsplit) == 2:
+        if len(datestrsplit[0]) == 4 and len(datestrsplit[1]) == 2:
+            return parse_calendar_date(isodatestr)
+
+
+    if len(datestrsplit) == 3:
+        if len(datestrsplit[0]) == 4 and len(datestrsplit[1]) == 2 and len(datestrsplit[2]) == 2:
+            return parse_calendar_date(isodatestr)
+
+    #Check case 2
+    if len(isodatestr) == 8 and isodatestr.find('-') == -1:
+        return parse_calendar_date(isodatestr)
+
+    #An ISO string may be a ordinal date representation if:
+    # 1) When split on a hyphen, the sizes of the parts are 4, 3
+    # 2) There are no hyphens, and the length is 7
+
+    #Check case 1
+    if len(datestrsplit) == 2:
+        if len(datestrsplit[0]) == 4 and len(datestrsplit[1]) == 3:
+            return parse_ordinal_date(isodatestr)
+
+    #Check case 2
+    if len(isodatestr) == 7 and isodatestr.find('-') == -1:
+        return parse_ordinal_date(isodatestr)
+
+    #None of the date representations match
+    raise ValueError('String is not an ISO8601 date, perhaps it represents a time or datetime.')
+
+def parse_time(isotimestr):
+    #Given a string in any ISO8601 time format, return a datetime.time object
+    #that corresponds to the given time. Fixed offset tzdata will be included
+    #if UTC offset is given in the input string. Valid time formats are:
+    #
+    #hh:mm:ss
+    #hhmmss
+    #hh:mm
+    #hhmm
+    #hh
+    #hh:mm:ssZ
+    #hhmmssZ
+    #hh:mmZ
+    #hhmmZ
+    #hhZ
+    #hh:mm:ss±hh:mm
+    #hhmmss±hh:mm
+    #hh:mm±hh:mm
+    #hhmm±hh:mm
+    #hh±hh:mm
+    #hh:mm:ss±hhmm
+    #hhmmss±hhmm
+    #hh:mm±hhmm
+    #hhmm±hhmm
+    #hh±hhmm
+    #hh:mm:ss±hh
+    #hhmmss±hh
+    #hh:mm±hh
+    #hhmm±hh
+    #hh±hh
+
+    #Split the string at the TZ, if necessary
+    if isotimestr.find('+') != -1:
+        timestr = isotimestr[0:isotimestr.find('+')]
+        tzstr = isotimestr[isotimestr.find('+'):]
+    elif isotimestr.find('-') != -1:
+        timestr = isotimestr[0:isotimestr.find('-')]
+        tzstr = isotimestr[isotimestr.find('-'):]
+    elif isotimestr.endswith('Z'):
+        timestr = isotimestr[:-1]
+        tzstr = 'Z'
+    else:
+        timestr = isotimestr
+        tzstr = None
+
+    if tzstr == None:
+        return parse_time_naive(timestr)
+    elif tzstr == 'Z':
+        return parse_time_naive(timestr).replace(tzinfo=UTCOffset('UTC', datetime.timedelta(hours=0)))
+    else:
+        return parse_time_naive(timestr).replace(tzinfo=parse_timezone(tzstr))
+
 def parse_year(yearstr):
     #yearstr is of the format Y[YYY]
     #
         #Since no 'time' is given, cast to a date
         return parseddatetime.date()
 
-def parse_time(timestr):
+def parse_time_naive(timestr):
     #timestr is of the format hh:mm:ss, hh:mm, hhmmss, hhmm, hh
     #
     #hh is between 0 and 24, 24 is not allowed in the Python time format, since
     #it represents midnight, a time of 00:00:00 is returned
     #
     #mm is between 0 and 60, with 60 used to denote a leap second
+    #
+    #No tzinfo will be included
 
     if timestr.count(':') == 2:
         #hh:mm:ss

aniso8601/test_aniso8601.py

 import aniso8601
 
 class TestParseFunctions(unittest.TestCase):
+    def test_parse_date(self):
+        date = aniso8601.parse_date('2013')
+        self.assertEqual(date.year, 2013)
+        self.assertEqual(date.month, 1)
+        self.assertEqual(date.day, 1)
+
+        date = aniso8601.parse_date('0001')
+        self.assertEqual(date.year, 1)
+        self.assertEqual(date.month, 1)
+        self.assertEqual(date.day, 1)
+
+        date = aniso8601.parse_date('19')
+        self.assertEqual(date.year, 1900)
+        self.assertEqual(date.month, 1)
+        self.assertEqual(date.day, 1)
+
+        date = aniso8601.parse_date('1981-04-05')
+        self.assertEqual(date.year, 1981)
+        self.assertEqual(date.month, 4)
+        self.assertEqual(date.day, 5)
+
+        date = aniso8601.parse_date('19810405')
+        self.assertEqual(date.year, 1981)
+        self.assertEqual(date.month, 4)
+        self.assertEqual(date.day, 5)
+
+        date = aniso8601.parse_date('1981-04')
+        self.assertEqual(date.year, 1981)
+        self.assertEqual(date.month, 4)
+        self.assertEqual(date.day, 1)
+
+        date = aniso8601.parse_date('2004-W53')
+        self.assertEqual(date.year, 2004)
+        self.assertEqual(date.month, 12)
+        self.assertEqual(date.weekday(), 0)
+
+        date = aniso8601.parse_date('2009-W01')
+        self.assertEqual(date.year, 2008)
+        self.assertEqual(date.month, 12)
+        self.assertEqual(date.weekday(), 0)
+
+        date = aniso8601.parse_date('2004-W53-6')
+        self.assertEqual(date.year, 2005)
+        self.assertEqual(date.month, 1)
+        self.assertEqual(date.day, 1)
+
+        date = aniso8601.parse_date('2004W53')
+        self.assertEqual(date.year, 2004)
+        self.assertEqual(date.month, 12)
+        self.assertEqual(date.weekday(), 0)
+
+        date = aniso8601.parse_date('2004W536')
+        self.assertEqual(date.year, 2005)
+        self.assertEqual(date.month, 1)
+        self.assertEqual(date.day, 1)
+
+        date = aniso8601.parse_date('1981-095')
+        self.assertEqual(date.year, 1981)
+        self.assertEqual(date.month, 4)
+        self.assertEqual(date.day, 5)
+
+        date = aniso8601.parse_date('1981095')
+        self.assertEqual(date.year, 1981)
+        self.assertEqual(date.month, 4)
+        self.assertEqual(date.day, 5)
+
+    def test_parse_time(self):
+        time = aniso8601.parse_time('01:23:45')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 23)
+        self.assertEqual(time.second, 45)
+
+        time = aniso8601.parse_time('24:00:00')
+        self.assertEqual(time.hour, 0)
+        self.assertEqual(time.minute, 0)
+        self.assertEqual(time.second, 0)
+
+        time = aniso8601.parse_time('23:21:28.512400')
+        self.assertEqual(time.hour, 23)
+        self.assertEqual(time.minute, 21)
+        self.assertEqual(time.second, 28)
+        self.assertEqual(time.microsecond, 512400)
+
+        time = aniso8601.parse_time('01:23')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 23)
+
+        time = aniso8601.parse_time('24:00')
+        self.assertEqual(time.hour, 0)
+        self.assertEqual(time.minute, 0)
+
+        time = aniso8601.parse_time('01:23.4567')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 23)
+        self.assertEqual(time.second, 27)
+        self.assertEqual(time.microsecond, 402000)
+
+        time = aniso8601.parse_time('012345')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 23)
+        self.assertEqual(time.second, 45)
+
+        time = aniso8601.parse_time('240000')
+        self.assertEqual(time.hour, 0)
+        self.assertEqual(time.minute, 0)
+        self.assertEqual(time.second, 0)
+
+        time = aniso8601.parse_time('0123')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 23)
+
+        time = aniso8601.parse_time('2400')
+        self.assertEqual(time.hour, 0)
+        self.assertEqual(time.minute, 0)
+
+        time = aniso8601.parse_time('01')
+        self.assertEqual(time.hour, 1)
+
+        time = aniso8601.parse_time('24')
+        self.assertEqual(time.hour, 0)
+
+        time = aniso8601.parse_time('232128.512400+00:00')
+        self.assertEqual(time.hour, 23)
+        self.assertEqual(time.minute, 21)
+        self.assertEqual(time.second, 28)
+        self.assertEqual(time.microsecond, 512400)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), '+00:00')
+
+        time = aniso8601.parse_time('0123.4567+00:00')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 23)
+        self.assertEqual(time.second, 27)
+        self.assertEqual(time.microsecond, 402000)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), '+00:00')
+
+        time = aniso8601.parse_time('01.4567+00:00')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 27)
+        self.assertEqual(time.second, 24)
+        self.assertEqual(time.microsecond, 120000)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), '+00:00')
+
+        time = aniso8601.parse_time('01:23:45+00:00')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 23)
+        self.assertEqual(time.second, 45)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), '+00:00')
+
+        time = aniso8601.parse_time('24:00:00+00:00')
+        self.assertEqual(time.hour, 0)
+        self.assertEqual(time.minute, 0)
+        self.assertEqual(time.second, 0)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), '+00:00')
+
+        time = aniso8601.parse_time('23:21:28.512400+00:00')
+        self.assertEqual(time.hour, 23)
+        self.assertEqual(time.minute, 21)
+        self.assertEqual(time.second, 28)
+        self.assertEqual(time.microsecond, 512400)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), '+00:00')
+
+        time = aniso8601.parse_time('01:23+00:00')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 23)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), '+00:00')
+
+        time = aniso8601.parse_time('24:00+00:00')
+        self.assertEqual(time.hour, 0)
+        self.assertEqual(time.minute, 0)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), '+00:00')
+
+        time = aniso8601.parse_time('01:23.4567+00:00')
+        self.assertEqual(time.hour, 1)
+        self.assertEqual(time.minute, 23)
+        self.assertEqual(time.second, 27)
+        self.assertEqual(time.microsecond, 402000)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), '+00:00')
+
+        time = aniso8601.parse_time('23:21:28.512400+11:15')
+        self.assertEqual(time.hour, 23)
+        self.assertEqual(time.minute, 21)
+        self.assertEqual(time.second, 28)
+        self.assertEqual(time.microsecond, 512400)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=11, minutes=15))
+        self.assertEqual(tzinfoobject.tzname(None), '+11:15')
+
+        time = aniso8601.parse_time('23:21:28.512400-12:34')
+        self.assertEqual(time.hour, 23)
+        self.assertEqual(time.minute, 21)
+        self.assertEqual(time.second, 28)
+        self.assertEqual(time.microsecond, 512400)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), -datetime.timedelta(hours=12, minutes=34))
+        self.assertEqual(tzinfoobject.tzname(None), '-12:34')
+
+        time = aniso8601.parse_time('23:21:28.512400Z')
+        self.assertEqual(time.hour, 23)
+        self.assertEqual(time.minute, 21)
+        self.assertEqual(time.second, 28)
+        self.assertEqual(time.microsecond, 512400)
+        tzinfoobject = time.tzinfo
+        self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0))
+        self.assertEqual(tzinfoobject.tzname(None), 'UTC')
+
     def test_parse_year(self):
         date = aniso8601.parse_year('2013')
         self.assertEqual(date.year, 2013)
         self.assertEqual(date.month, 4)
         self.assertEqual(date.day, 5)
 
-    def test_parse_time(self):
-        time = aniso8601.parse_time('01:23:45')
+    def test_parse_time_naive(self):
+        time = aniso8601.parse_time_naive('01:23:45')
         self.assertEqual(time.hour, 1)
         self.assertEqual(time.minute, 23)
         self.assertEqual(time.second, 45)
 
-        time = aniso8601.parse_time('24:00:00')
+        time = aniso8601.parse_time_naive('24:00:00')
         self.assertEqual(time.hour, 0)
         self.assertEqual(time.minute, 0)
         self.assertEqual(time.second, 0)
 
-        time = aniso8601.parse_time('23:21:28.512400')
+        time = aniso8601.parse_time_naive('23:21:28.512400')
         self.assertEqual(time.hour, 23)
         self.assertEqual(time.minute, 21)
         self.assertEqual(time.second, 28)
         self.assertEqual(time.microsecond, 512400)
 
-        time = aniso8601.parse_time('01:23')
+        time = aniso8601.parse_time_naive('01:23')
         self.assertEqual(time.hour, 1)
         self.assertEqual(time.minute, 23)
 
-        time = aniso8601.parse_time('24:00')
+        time = aniso8601.parse_time_naive('24:00')
         self.assertEqual(time.hour, 0)
         self.assertEqual(time.minute, 0)
 
-        time = aniso8601.parse_time('01:23.4567')
+        time = aniso8601.parse_time_naive('01:23.4567')
         self.assertEqual(time.hour, 1)
         self.assertEqual(time.minute, 23)
         self.assertEqual(time.second, 27)
         self.assertEqual(time.microsecond, 402000)
 
-        time = aniso8601.parse_time('012345')
+        time = aniso8601.parse_time_naive('012345')
         self.assertEqual(time.hour, 1)
         self.assertEqual(time.minute, 23)
         self.assertEqual(time.second, 45)
 
-        time = aniso8601.parse_time('240000')
+        time = aniso8601.parse_time_naive('240000')
         self.assertEqual(time.hour, 0)
         self.assertEqual(time.minute, 0)
         self.assertEqual(time.second, 0)
 
-        time = aniso8601.parse_time('0123')
+        time = aniso8601.parse_time_naive('0123')
         self.assertEqual(time.hour, 1)
         self.assertEqual(time.minute, 23)
 
-        time = aniso8601.parse_time('2400')
+        time = aniso8601.parse_time_naive('2400')
         self.assertEqual(time.hour, 0)
         self.assertEqual(time.minute, 0)
 
-        time = aniso8601.parse_time('01')
+        time = aniso8601.parse_time_naive('01')
         self.assertEqual(time.hour, 1)
 
-        time = aniso8601.parse_time('24')
+        time = aniso8601.parse_time_naive('24')
         self.assertEqual(time.hour, 0)
 
-        time = aniso8601.parse_time('232128.512400')
+        time = aniso8601.parse_time_naive('232128.512400')
         self.assertEqual(time.hour, 23)
         self.assertEqual(time.minute, 21)
         self.assertEqual(time.second, 28)
         self.assertEqual(time.microsecond, 512400)
 
-        time = aniso8601.parse_time('0123.4567')
+        time = aniso8601.parse_time_naive('0123.4567')
         self.assertEqual(time.hour, 1)
         self.assertEqual(time.minute, 23)
         self.assertEqual(time.second, 27)
         self.assertEqual(time.microsecond, 402000)
 
-        time = aniso8601.parse_time('01.4567')
+        time = aniso8601.parse_time_naive('01.4567')
         self.assertEqual(time.hour, 1)
         self.assertEqual(time.minute, 27)
         self.assertEqual(time.second, 24)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.