def test_parse_datetime(self): testtuples = (('1981-04-05T23:21:28.512400Z', (('1981', '04', '05', None, None, None, 'date'), ('23', '21', '28.512400', (False, True, None, None, 'Z', 'timezone'), 'time'))), ('1981095T23:21:28.512400-12:34', (('1981', None, None, None, None, '095', 'date'), ('23', '21', '28.512400', (True, None, '12', '34', '-12:34', 'timezone'), 'time'))), ('19810405T23:21:28+00', (('1981', '04', '05', None, None, None, 'date'), ('23', '21', '28', (False, None, '00', None, '+00', 'timezone'), 'time'))), ('19810405T23:21:28+00:00', (('1981', '04', '05', None, None, None, 'date'), ('23', '21', '28', (False, None, '00', '00', '+00:00', 'timezone'), 'time')))) for testtuple in testtuples: with mock.patch.object(aniso8601.builder.PythonTimeBuilder, 'build_datetime') as mockBuildDateTime: mockBuildDateTime.return_value = testtuple[1] result = parse_datetime(testtuple[0]) self.assertEqual(result, testtuple[1]) mockBuildDateTime.assert_called_once_with(*testtuple[1])
def test_parse_datetime(self): resultdatetime = parse_datetime('1981-04-05T23:21:28.512400Z') self.assertEqual(resultdatetime.year, 1981) self.assertEqual(resultdatetime.month, 4) self.assertEqual(resultdatetime.day, 5) self.assertEqual(resultdatetime.hour, 23) self.assertEqual(resultdatetime.minute, 21) self.assertEqual(resultdatetime.second, 28) self.assertEqual(resultdatetime.microsecond, 512400) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0)) self.assertEqual(tzinfoobject.tzname(None), 'UTC') resultdatetime = parse_datetime('1981095T23:21:28.512400-12:34') self.assertEqual(resultdatetime.year, 1981) self.assertEqual(resultdatetime.month, 4) self.assertEqual(resultdatetime.day, 5) self.assertEqual(resultdatetime.hour, 23) self.assertEqual(resultdatetime.minute, 21) self.assertEqual(resultdatetime.second, 28) self.assertEqual(resultdatetime.microsecond, 512400) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), -datetime.timedelta(hours=12, minutes=34)) self.assertEqual(tzinfoobject.tzname(None), '-12:34') resultdatetime = parse_datetime('19810405T23:21:28+00') self.assertEqual(resultdatetime.year, 1981) self.assertEqual(resultdatetime.month, 4) self.assertEqual(resultdatetime.day, 5) self.assertEqual(resultdatetime.hour, 23) self.assertEqual(resultdatetime.minute, 21) self.assertEqual(resultdatetime.second, 28) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0)) self.assertEqual(tzinfoobject.tzname(None), '+00') resultdatetime = parse_datetime('19810405T23:21:28+00:00') self.assertEqual(resultdatetime.year, 1981) self.assertEqual(resultdatetime.month, 4) self.assertEqual(resultdatetime.day, 5) self.assertEqual(resultdatetime.hour, 23) self.assertEqual(resultdatetime.minute, 21) self.assertEqual(resultdatetime.second, 28) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0)) self.assertEqual(tzinfoobject.tzname(None), '+00:00')
def test_parse_datetime_spaceseperated(self): resultdatetime = parse_datetime('2004-W53-6 23:21:28.512400-12:34', ' ') self.assertEqual(resultdatetime.year, 2005) self.assertEqual(resultdatetime.month, 1) self.assertEqual(resultdatetime.day, 1) self.assertEqual(resultdatetime.hour, 23) self.assertEqual(resultdatetime.minute, 21) self.assertEqual(resultdatetime.second, 28) self.assertEqual(resultdatetime.microsecond, 512400) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), -datetime.timedelta(hours=12, minutes=34)) self.assertEqual(tzinfoobject.tzname(None), '-12:34')
def test_parse_datetime_mockbuilder(self): mockBuilder = mock.Mock() expectedargs = (('1981', None, None, None, None, '095', 'date'), ('23', '21', '28.512400', (True, None, '12', '34', '-12:34', 'timezone'), 'time')) mockBuilder.build_datetime.return_value = expectedargs result = parse_datetime('1981095T23:21:28.512400-12:34', builder=mockBuilder) self.assertEqual(result, expectedargs) mockBuilder.build_datetime.assert_called_once_with(*expectedargs)
def test_parse_datetime_commadelimited(self): expectedargs = (('1981', '04', '05', None, None, None, 'date'), ('23', '21', '28.512400', (False, True, None, None, 'Z', 'timezone'), 'time')) with mock.patch.object(aniso8601.time.PythonTimeBuilder, 'build_datetime') as mockBuildDateTime: mockBuildDateTime.return_value = expectedargs result = parse_datetime('1981-04-05,23:21:28,512400Z', delimiter=',') self.assertEqual(result, expectedargs) mockBuildDateTime.assert_called_once_with(*expectedargs)
def test_parse_datetime_spacedelimited(self): expectedargs = (('2004', None, None, '53', '6', None, 'date'), ('23', '21', '28.512400', (True, None, '12', '34', '-12:34', 'timezone'), 'time')) with mock.patch.object(aniso8601.time.PythonTimeBuilder, 'build_datetime') as mockBuildDateTime: mockBuildDateTime.return_value = expectedargs result = parse_datetime('2004-W53-6 23:21:28.512400-12:34', delimiter=' ') self.assertEqual(result, expectedargs) mockBuildDateTime.assert_called_once_with(*expectedargs)
def test_parse_datetime_mockbuilder(self): mockBuilder = mock.Mock() expectedargs = ( DateTuple("1981", None, None, None, None, "095"), TimeTuple( "23", "21", "28.512400", TimezoneTuple(True, None, "12", "34", "-12:34") ), ) mockBuilder.build_datetime.return_value = expectedargs result = parse_datetime("1981095T23:21:28.512400-12:34", builder=mockBuilder) self.assertEqual(result, expectedargs) mockBuilder.build_datetime.assert_called_once_with(*expectedargs)
def test_parse_datetime_spaceseperated(self): expectedargs = (('2004', None, None, '53', '6', None, 'date'), ('23', '21', '28.512400', (True, None, '12', '34', '-12:34', 'timezone'), 'time')) with mock.patch.object(aniso8601.builder.PythonTimeBuilder, 'build_datetime') as mockBuildDateTime: mockBuildDateTime.return_value = expectedargs result = parse_datetime('2004-W53-6 23:21:28.512400-12:34', delimiter=' ') self.assertEqual(result, expectedargs) mockBuildDateTime.assert_called_once_with(*expectedargs)
def test_parse_datetime_spaceseperated(self): resultdatetime = parse_datetime('2004-W53-6 23:21:28.512400-12:34', ' ') self.assertEqual( resultdatetime.replace(tzinfo=None), datetime.datetime(2005, 1, 1, hour=23, minute=21, second=28, microsecond=512400)) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), -datetime.timedelta(hours=12, minutes=34)) self.assertEqual(tzinfoobject.tzname(None), '-12:34')
def test_parse_datetime_commadelimited(self): expectedargs = ( DateTuple("1981", "04", "05", None, None, None), TimeTuple( "23", "21", "28.512400", TimezoneTuple(False, True, None, None, "Z") ), ) with mock.patch.object( aniso8601.time.PythonTimeBuilder, "build_datetime" ) as mockBuildDateTime: mockBuildDateTime.return_value = expectedargs result = parse_datetime("1981-04-05,23:21:28,512400Z", delimiter=",") self.assertEqual(result, expectedargs) mockBuildDateTime.assert_called_once_with(*expectedargs)
def test_parse_datetime_spacedelimited(self): expectedargs = ( DateTuple("2004", None, None, "53", "6", None), TimeTuple( "23", "21", "28.512400", TimezoneTuple(True, None, "12", "34", "-12:34") ), ) with mock.patch.object( aniso8601.time.PythonTimeBuilder, "build_datetime" ) as mockBuildDateTime: mockBuildDateTime.return_value = expectedargs result = parse_datetime("2004-W53-6 23:21:28.512400-12:34", delimiter=" ") self.assertEqual(result, expectedargs) mockBuildDateTime.assert_called_once_with(*expectedargs)
def test_parse_datetime(self): testtuples = (('2019-06-05T01:03:11,858714', (DateTuple('2019', '06', '05', None, None, None), TimeTuple('01', '03', '11.858714', None))), ('2019-06-05T01:03:11.858714', (DateTuple('2019', '06', '05', None, None, None), TimeTuple('01', '03', '11.858714', None))), ('1981-04-05T23:21:28.512400Z', (DateTuple('1981', '04', '05', None, None, None), TimeTuple('23', '21', '28.512400', TimezoneTuple(False, True, None, None, 'Z')))), ('1981095T23:21:28.512400-12:34', (DateTuple('1981', None, None, None, None, '095'), TimeTuple( '23', '21', '28.512400', TimezoneTuple(True, None, '12', '34', '-12:34')))), ('19810405T23:21:28+00', (DateTuple('1981', '04', '05', None, None, None), TimeTuple( '23', '21', '28', TimezoneTuple(False, None, '00', None, '+00')))), ('19810405T23:21:28+00:00', (DateTuple('1981', '04', '05', None, None, None), TimeTuple( '23', '21', '28', TimezoneTuple(False, None, '00', '00', '+00:00'))))) for testtuple in testtuples: with mock.patch.object(aniso8601.time.PythonTimeBuilder, 'build_datetime') as mockBuildDateTime: mockBuildDateTime.return_value = testtuple[1] result = parse_datetime(testtuple[0]) self.assertEqual(result, testtuple[1]) mockBuildDateTime.assert_called_once_with(*testtuple[1])
def parse_interval(isointervalstr, intervaldelimiter='/', datetimedelimiter='T', relative=False): #Given a string representing an ISO 8601 interval, return a #tuple of datetime.date or date.datetime objects representing the beginning #and end of the specified interval. Valid formats are: # #<start>/<end> #<start>/<duration> #<duration>/<end> # #The <start> and <end> values can represent dates, or datetimes, #not times. # #The format: # #<duration> # #Is expressly not supported as there is no way to provide the addtional #required context. firstpart, secondpart = isointervalstr.split(intervaldelimiter) if firstpart[0] == 'P': #<duration>/<end> #Notice that these are not returned 'in order' (earlier to later), this #is to maintain consistency with parsing <start>/<end> durations, as #well as making repeating interval code cleaner. Users who desire #durations to be in order can use the 'sorted' operator. #We need to figure out if <end> is a date, or a datetime if secondpart.find(datetimedelimiter) != -1: #<end> is a datetime duration = parse_duration(firstpart, relative=relative) enddatetime = parse_datetime(secondpart, delimiter=datetimedelimiter) return (enddatetime, enddatetime - duration) else: #<end> must just be a date duration = parse_duration(firstpart, relative=relative) enddate = parse_date(secondpart) #See if we need to upconvert to datetime to preserve resolution if firstpart.find(datetimedelimiter) != -1: return (enddate, datetime.combine(enddate, datetime.min.time()) - duration) else: return (enddate, enddate - duration) elif secondpart[0] == 'P': #<start>/<duration> #We need to figure out if <start> is a date, or a datetime if firstpart.find(datetimedelimiter) != -1: #<end> is a datetime duration = parse_duration(secondpart, relative=relative) startdatetime = parse_datetime(firstpart, delimiter=datetimedelimiter) return (startdatetime, startdatetime + duration) else: #<start> must just be a date duration = parse_duration(secondpart, relative=relative) startdate = parse_date(firstpart) #See if we need to upconvert to datetime to preserve resolution if secondpart.find(datetimedelimiter) != -1: return (startdate, datetime.combine(startdate, datetime.min.time()) + duration) else: return (startdate, startdate + duration) else: #<start>/<end> if firstpart.find(datetimedelimiter) != -1 and secondpart.find( datetimedelimiter) != -1: #Both parts are datetimes return (parse_datetime(firstpart, delimiter=datetimedelimiter), parse_datetime(secondpart, delimiter=datetimedelimiter)) elif firstpart.find(datetimedelimiter) != -1 and secondpart.find( datetimedelimiter) == -1: #First part is a datetime, second part is a date return (parse_datetime(firstpart, delimiter=datetimedelimiter), parse_date(secondpart)) elif firstpart.find(datetimedelimiter) == -1 and secondpart.find( datetimedelimiter) != -1: #First part is a date, second part is a datetime return (parse_date(firstpart), parse_datetime(secondpart, delimiter=datetimedelimiter)) else: #Both parts are dates return (parse_date(firstpart), parse_date(secondpart))
def _parse_interval( isointervalstr, builder, intervaldelimiter="/", datetimedelimiter="T" ): # Returns a tuple containing the start of the interval, the end of the # interval, and or the interval duration firstpart, secondpart = isointervalstr.split(intervaldelimiter) if firstpart[0] == "P": # <duration>/<end> # Notice that these are not returned 'in order' (earlier to later), this # is to maintain consistency with parsing <start>/<end> durations, as # well as making repeating interval code cleaner. Users who desire # durations to be in order can use the 'sorted' operator. # We need to figure out if <end> is a date, or a datetime if secondpart.find(datetimedelimiter) != -1: # <end> is a datetime duration = parse_duration(firstpart, builder=TupleBuilder) enddatetime = parse_datetime( secondpart, delimiter=datetimedelimiter, builder=TupleBuilder ) return builder.build_interval(end=enddatetime, duration=duration) # <end> must just be a date duration = parse_duration(firstpart, builder=TupleBuilder) enddate = parse_date(secondpart, builder=TupleBuilder) return builder.build_interval(end=enddate, duration=duration) elif secondpart[0] == "P": # <start>/<duration> # We need to figure out if <start> is a date, or a datetime if firstpart.find(datetimedelimiter) != -1: # <start> is a datetime duration = parse_duration(secondpart, builder=TupleBuilder) startdatetime = parse_datetime( firstpart, delimiter=datetimedelimiter, builder=TupleBuilder ) return builder.build_interval(start=startdatetime, duration=duration) # <start> must just be a date duration = parse_duration(secondpart, builder=TupleBuilder) startdate = parse_date(firstpart, builder=TupleBuilder) return builder.build_interval(start=startdate, duration=duration) # <start>/<end> if ( firstpart.find(datetimedelimiter) != -1 and secondpart.find(datetimedelimiter) != -1 ): # Both parts are datetimes start_datetime = parse_datetime( firstpart, delimiter=datetimedelimiter, builder=TupleBuilder ) end_datetime = parse_datetime( secondpart, delimiter=datetimedelimiter, builder=TupleBuilder ) return builder.build_interval(start=start_datetime, end=end_datetime) elif ( firstpart.find(datetimedelimiter) != -1 and secondpart.find(datetimedelimiter) == -1 ): # First part is a datetime, second part is a date start_datetime = parse_datetime( firstpart, delimiter=datetimedelimiter, builder=TupleBuilder ) end_date = parse_date(secondpart, builder=TupleBuilder) return builder.build_interval(start=start_datetime, end=end_date) elif ( firstpart.find(datetimedelimiter) == -1 and secondpart.find(datetimedelimiter) != -1 ): # First part is a date, second part is a datetime start_date = parse_date(firstpart, builder=TupleBuilder) end_datetime = parse_datetime( secondpart, delimiter=datetimedelimiter, builder=TupleBuilder ) return builder.build_interval(start=start_date, end=end_datetime) # Both parts are dates start_date = parse_date(firstpart, builder=TupleBuilder) end_date = parse_date(secondpart, builder=TupleBuilder) return builder.build_interval(start=start_date, end=end_date)
def _parse_interval_parts(isointervalstr, intervaldelimiter='/', datetimedelimiter='T', relative=False): #Returns a tuple containing the start of the interval, the end of the interval, and the interval timedelta firstpart, secondpart = isointervalstr.split(intervaldelimiter) if firstpart[0] == 'P': #<duration>/<end> #Notice that these are not returned 'in order' (earlier to later), this #is to maintain consistency with parsing <start>/<end> durations, as #well as making repeating interval code cleaner. users_dispatcher who desire #durations to be in order can use the 'sorted' operator. #We need to figure out if <end> is a date, or a datetime if secondpart.find(datetimedelimiter) != -1: #<end> is a datetime duration = parse_duration(firstpart, relative=relative) enddatetime = parse_datetime(secondpart, delimiter=datetimedelimiter) return (enddatetime, enddatetime - duration, -duration) else: #<end> must just be a date duration = parse_duration(firstpart, relative=relative) enddate = parse_date(secondpart) #See if we need to upconvert to datetime to preserve resolution if firstpart.find(datetimedelimiter) != -1: return (enddate, datetime.combine(enddate, datetime.min.time()) - duration, -duration) else: return (enddate, enddate - duration, -duration) elif secondpart[0] == 'P': #<start>/<duration> #We need to figure out if <start> is a date, or a datetime if firstpart.find(datetimedelimiter) != -1: #<start> is a datetime duration = parse_duration(secondpart, relative=relative) startdatetime = parse_datetime(firstpart, delimiter=datetimedelimiter) return (startdatetime, startdatetime + duration, duration) else: #<start> must just be a date duration = parse_duration(secondpart, relative=relative) startdate = parse_date(firstpart) #See if we need to upconvert to datetime to preserve resolution if secondpart.find(datetimedelimiter) != -1: return (startdate, datetime.combine(startdate, datetime.min.time()) + duration, duration) else: return (startdate, startdate + duration, duration) else: #<start>/<end> if firstpart.find(datetimedelimiter) != -1 and secondpart.find( datetimedelimiter) != -1: #Both parts are datetimes start_datetime = parse_datetime(firstpart, delimiter=datetimedelimiter) end_datetime = parse_datetime(secondpart, delimiter=datetimedelimiter) return (start_datetime, end_datetime, end_datetime - start_datetime) elif firstpart.find(datetimedelimiter) != -1 and secondpart.find( datetimedelimiter) == -1: #First part is a datetime, second part is a date start_datetime = parse_datetime(firstpart, delimiter=datetimedelimiter) end_date = parse_date(secondpart) return (start_datetime, end_date, datetime.combine(end_date, datetime.min.time()) - start_datetime) elif firstpart.find(datetimedelimiter) == -1 and secondpart.find( datetimedelimiter) != -1: #First part is a date, second part is a datetime start_date = parse_date(firstpart) end_datetime = parse_datetime(secondpart, delimiter=datetimedelimiter) return (start_date, end_datetime, end_datetime - datetime.combine(start_date, datetime.min.time())) else: #Both parts are dates start_date = parse_date(firstpart) end_date = parse_date(secondpart) return (start_date, end_date, end_date - start_date)
def _parse_interval_parts(isointervalstr, intervaldelimiter='/', datetimedelimiter='T', relative=False): #Returns a tuple containing the start of the interval, the end of the interval, and the interval timedelta firstpart, secondpart = isointervalstr.split(intervaldelimiter) if firstpart[0] == 'P': #<duration>/<end> #Notice that these are not returned 'in order' (earlier to later), this #is to maintain consistency with parsing <start>/<end> durations, as #well as making repeating interval code cleaner. Users who desire #durations to be in order can use the 'sorted' operator. #We need to figure out if <end> is a date, or a datetime if secondpart.find(datetimedelimiter) != -1: #<end> is a datetime duration = parse_duration(firstpart, relative=relative) enddatetime = parse_datetime(secondpart, delimiter=datetimedelimiter) return (enddatetime, enddatetime - duration, -duration) else: #<end> must just be a date duration = parse_duration(firstpart, relative=relative) enddate = parse_date(secondpart) #See if we need to upconvert to datetime to preserve resolution if firstpart.find(datetimedelimiter) != -1: return (enddate, datetime.combine(enddate, datetime.min.time()) - duration, -duration) else: return (enddate, enddate - duration, -duration) elif secondpart[0] == 'P': #<start>/<duration> #We need to figure out if <start> is a date, or a datetime if firstpart.find(datetimedelimiter) != -1: #<start> is a datetime duration = parse_duration(secondpart, relative=relative) startdatetime = parse_datetime(firstpart, delimiter=datetimedelimiter) return (startdatetime, startdatetime + duration, duration) else: #<start> must just be a date duration = parse_duration(secondpart, relative=relative) startdate = parse_date(firstpart) #See if we need to upconvert to datetime to preserve resolution if secondpart.find(datetimedelimiter) != -1: return (startdate, datetime.combine(startdate, datetime.min.time()) + duration, duration) else: return (startdate, startdate + duration, duration) else: #<start>/<end> if firstpart.find(datetimedelimiter) != -1 and secondpart.find(datetimedelimiter) != -1: #Both parts are datetimes start_datetime = parse_datetime(firstpart, delimiter=datetimedelimiter) end_datetime = parse_datetime(secondpart, delimiter=datetimedelimiter) return (start_datetime, end_datetime, end_datetime - start_datetime) elif firstpart.find(datetimedelimiter) != -1 and secondpart.find(datetimedelimiter) == -1: #First part is a datetime, second part is a date start_datetime = parse_datetime(firstpart, delimiter=datetimedelimiter) end_date = parse_date(secondpart) return (start_datetime, end_date, datetime.combine(end_date, datetime.min.time()) - start_datetime) elif firstpart.find(datetimedelimiter) == -1 and secondpart.find(datetimedelimiter) != -1: #First part is a date, second part is a datetime start_date = parse_date(firstpart) end_datetime = parse_datetime(secondpart, delimiter=datetimedelimiter) return (start_date, end_datetime, end_datetime - datetime.combine(start_date, datetime.min.time())) else: #Both parts are dates start_date = parse_date(firstpart) end_date = parse_date(secondpart) return (start_date, end_date, end_date - start_date)
def test_parse_datetime(self): testtuples = ( ( "2019-06-05T01:03:11,858714", ( ("2019", "06", "05", None, None, None, "date"), ("01", "03", "11.858714", None, "time"), ), ), ( "2019-06-05T01:03:11.858714", ( ("2019", "06", "05", None, None, None, "date"), ("01", "03", "11.858714", None, "time"), ), ), ( "1981-04-05T23:21:28.512400Z", ( ("1981", "04", "05", None, None, None, "date"), ( "23", "21", "28.512400", (False, True, None, None, "Z", "timezone"), "time", ), ), ), ( "1981095T23:21:28.512400-12:34", ( ("1981", None, None, None, None, "095", "date"), ( "23", "21", "28.512400", (True, None, "12", "34", "-12:34", "timezone"), "time", ), ), ), ( "19810405T23:21:28+00", ( ("1981", "04", "05", None, None, None, "date"), ( "23", "21", "28", (False, None, "00", None, "+00", "timezone"), "time", ), ), ), ( "19810405T23:21:28+00:00", ( ("1981", "04", "05", None, None, None, "date"), ( "23", "21", "28", (False, None, "00", "00", "+00:00", "timezone"), "time", ), ), ), ) for testtuple in testtuples: with mock.patch.object(aniso8601.time.PythonTimeBuilder, "build_datetime") as mockBuildDateTime: mockBuildDateTime.return_value = testtuple[1] result = parse_datetime(testtuple[0]) self.assertEqual(result, testtuple[1]) mockBuildDateTime.assert_called_once_with(*testtuple[1])
def test_parse_datetime(self): resultdatetime = parse_datetime('1981-04-05T23:21:28.512400Z') self.assertEqual(resultdatetime.year, 1981) self.assertEqual(resultdatetime.month, 4) self.assertEqual(resultdatetime.day, 5) self.assertEqual(resultdatetime.hour, 23) self.assertEqual(resultdatetime.minute, 21) self.assertEqual(resultdatetime.second, 28) self.assertEqual(resultdatetime.microsecond, 512400) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0)) self.assertEqual(tzinfoobject.tzname(None), 'UTC') resultdatetime = parse_datetime('1981095T23:21:28.512400-12:34') self.assertEqual(resultdatetime.year, 1981) self.assertEqual(resultdatetime.month, 4) self.assertEqual(resultdatetime.day, 5) self.assertEqual(resultdatetime.hour, 23) self.assertEqual(resultdatetime.minute, 21) self.assertEqual(resultdatetime.second, 28) self.assertEqual(resultdatetime.microsecond, 512400) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), -datetime.timedelta(hours=12, minutes=34)) self.assertEqual(tzinfoobject.tzname(None), '-12:34') resultdatetime = parse_datetime('19810405T23:21:28+00') self.assertEqual(resultdatetime.year, 1981) self.assertEqual(resultdatetime.month, 4) self.assertEqual(resultdatetime.day, 5) self.assertEqual(resultdatetime.hour, 23) self.assertEqual(resultdatetime.minute, 21) self.assertEqual(resultdatetime.second, 28) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0)) self.assertEqual(tzinfoobject.tzname(None), '+00') resultdatetime = parse_datetime('19810405T23:21:28+00:00') self.assertEqual(resultdatetime.year, 1981) self.assertEqual(resultdatetime.month, 4) self.assertEqual(resultdatetime.day, 5) self.assertEqual(resultdatetime.hour, 23) self.assertEqual(resultdatetime.minute, 21) self.assertEqual(resultdatetime.second, 28) tzinfoobject = resultdatetime.tzinfo self.assertEqual(tzinfoobject.utcoffset(None), datetime.timedelta(hours=0)) self.assertEqual(tzinfoobject.tzname(None), '+00:00') #https://bitbucket.org/nielsenb/aniso8601/issues/13/parsing-of-leap-second-gives-wildly with self.assertRaises(ValueError): parse_datetime('2016-12-31T23:59:60+00:00') with self.assertRaises(ValueError): parse_datetime('2016-12-31T23:59:60') with self.assertRaises(ValueError): parse_datetime('1981-04-05T00:00:60') with self.assertRaises(ValueError): parse_datetime('1981-04-05T00:00:60Z') with self.assertRaises(ValueError): parse_datetime('1981-04-05T00:00:60+00:00') with self.assertRaises(ValueError): parse_datetime('1981-04-05T00:61') with self.assertRaises(ValueError): parse_datetime('1981-04-05T00:61Z') with self.assertRaises(ValueError): parse_datetime('1981-04-05T00:61+00:00')
def test_parse_datetime_bounds(self): #Leap seconds not supported #https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is #https://bitbucket.org/nielsenb/aniso8601/issues/13/parsing-of-leap-second-gives-wildly with self.assertRaises(LeapSecondError): parse_datetime('2016-12-31T23:59:60+00:00') with self.assertRaises(LeapSecondError): parse_datetime('2016-12-31T23:59:60') with self.assertRaises(LeapSecondError): parse_datetime('2016-12-31T23:59:60Z') #Seconds can't be greater than 60 with self.assertRaises(SecondsOutOfBoundsError): parse_datetime('1981-04-05T00:00:60') with self.assertRaises(SecondsOutOfBoundsError): parse_datetime('1981-04-05T00:00:60Z') with self.assertRaises(SecondsOutOfBoundsError): parse_datetime('1981-04-05T00:00:60+00:00') with self.assertRaises(SecondsOutOfBoundsError): parse_datetime('2016-12-31T23:59:61+00:00') with self.assertRaises(SecondsOutOfBoundsError): parse_datetime('2016-12-31T23:59:61') with self.assertRaises(SecondsOutOfBoundsError): parse_datetime('1981-04-05T00:00:61') with self.assertRaises(SecondsOutOfBoundsError): parse_datetime('1981-04-05T00:00:61Z') with self.assertRaises(SecondsOutOfBoundsError): parse_datetime('1981-04-05T00:00:61+00:00') #Minutes can't be greater than 60 with self.assertRaises(MinutesOutOfBoundsError): parse_datetime('1981-04-05T00:61') with self.assertRaises(MinutesOutOfBoundsError): parse_datetime('1981-04-05T00:61Z') with self.assertRaises(MinutesOutOfBoundsError): parse_datetime('1981-04-05T00:61+00:00')
def test_parse_datetime_badtype(self): testtuples = (None, 1, False, 1.234) for testtuple in testtuples: with self.assertRaises(ValueError): parse_datetime(testtuple, builder=None)
def parse_interval(isointervalstr, intervaldelimiter='/', datetimedelimiter='T'): #Given a string representing an ISO8601 interval, return a #tuple of datetime.date or date.datetime objects representing the beginning #and end of the specified interval. Valid formats are: # #<start>/<end> #<start>/<duration> #<duration>/<end> # #The <start> and <end> values can represent dates, or datetimes, #not times. # #The format: # #<duration> # #Is expressly not supported as there is no way to provide the addtional #required context. firstpart, secondpart = isointervalstr.split(intervaldelimiter) if firstpart[0] == 'P': #<duration>/<end> #Notice that these are not returned 'in order' (earlier to later), this #is to maintain consistency with parsing <start>/<end> durations, as #well as making repeating interval code cleaner. Users who desire #durations to be in order can use the 'sorted' operator. #We need to figure out if <end> is a date, or a datetime if secondpart.find(datetimedelimiter) != -1: #<end> is a datetime duration = parse_duration(firstpart) enddatetime = parse_datetime(secondpart, delimiter=datetimedelimiter) return (enddatetime, enddatetime - duration) else: #<end> must just be a date duration = parse_duration(firstpart) enddate = parse_date(secondpart) #See if we need to upconvert to datetime to preserve resolution if firstpart.find(datetimedelimiter) != -1: return (enddate, datetime.combine(enddate, datetime.min.time()) - duration) else: return (enddate, enddate - duration) elif secondpart[0] == 'P': #<start>/<duration> #We need to figure out if <start> is a date, or a datetime if firstpart.find(datetimedelimiter) != -1: #<end> is a datetime duration = parse_duration(secondpart) startdatetime = parse_datetime(firstpart, delimiter=datetimedelimiter) return (startdatetime, startdatetime + duration) else: #<start> must just be a date duration = parse_duration(secondpart) startdate = parse_date(firstpart) #See if we need to upconvert to datetime to preserve resolution if secondpart.find(datetimedelimiter) != -1: return (startdate, datetime.combine(startdate, datetime.min.time()) + duration) else: return (startdate, startdate + duration) else: #<start>/<end> if firstpart.find(datetimedelimiter) != -1 and secondpart.find(datetimedelimiter) != -1: #Both parts are datetimes return (parse_datetime(firstpart, delimiter=datetimedelimiter), parse_datetime(secondpart, delimiter=datetimedelimiter)) elif firstpart.find(datetimedelimiter) != -1 and secondpart.find(datetimedelimiter) == -1: #First part is a datetime, second part is a date return (parse_datetime(firstpart, delimiter=datetimedelimiter), parse_date(secondpart)) elif firstpart.find(datetimedelimiter) == -1 and secondpart.find(datetimedelimiter) != -1: #First part is a date, second part is a datetime return (parse_date(firstpart), parse_datetime(secondpart, delimiter=datetimedelimiter)) else: #Both parts are dates return (parse_date(firstpart), parse_date(secondpart))