def test_parse_duration_prescribed_relative(self): resultduration = _parse_duration_prescribed('P1Y', True) self.assertEqual(resultduration, dateutil.relativedelta.relativedelta(years=1)) resultduration = _parse_duration_prescribed('P1M', True) self.assertEqual(resultduration, dateutil.relativedelta.relativedelta(months=1)) #Add the relative ‘days’ argument to the absolute day. Notice that the ‘weeks’ argument is multiplied by 7 and added to ‘days’. #http://dateutil.readthedocs.org/en/latest/relativedelta.html resultduration = _parse_duration_prescribed('P1W', True) self.assertEqual(resultduration, dateutil.relativedelta.relativedelta(days=7)) resultduration = _parse_duration_prescribed('P1.5W', True) self.assertEqual(resultduration, dateutil.relativedelta.relativedelta(days=10.5)) #Make sure we truncate, not round #https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is resultduration = parse_duration('PT0.0000001S', relative=True) self.assertEqual(resultduration, dateutil.relativedelta.relativedelta(0)) resultduration = parse_duration('PT2.0000048S', relative=True) self.assertEqual( resultduration, dateutil.relativedelta.relativedelta(seconds=2.000004))
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 len(firstpart) == 0 or len(secondpart) == 0: raise ISOFormatError( '{0} is not a valid ISO 8601 interval'.format(isointervalstr)) 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. duration = parse_duration(firstpart, builder=TupleBuilder) #We need to figure out if <end> is a date, or a datetime if secondpart.find(datetimedelimiter) != -1: #<end> is a datetime endtuple = parse_datetime(secondpart, delimiter=datetimedelimiter, builder=TupleBuilder) else: endtuple = parse_date(secondpart, builder=TupleBuilder) return builder.build_interval(end=endtuple, duration=duration) elif secondpart[0] == 'P': #<start>/<duration> #We need to figure out if <start> is a date, or a datetime duration = parse_duration(secondpart, builder=TupleBuilder) if firstpart.find(datetimedelimiter) != -1: #<start> is a datetime starttuple = parse_datetime(firstpart, delimiter=datetimedelimiter, builder=TupleBuilder) else: #<start> must just be a date starttuple = parse_date(firstpart, builder=TupleBuilder) return builder.build_interval(start=starttuple, duration=duration) #<start>/<end> if firstpart.find(datetimedelimiter) != -1: #Both parts are datetimes starttuple = parse_datetime(firstpart, delimiter=datetimedelimiter, builder=TupleBuilder) else: starttuple = parse_date(firstpart, builder=TupleBuilder) endtuple = _parse_interval_end(secondpart, starttuple, datetimedelimiter) return builder.build_interval(start=starttuple, end=endtuple)
def test_parse_duration_suffixgarbage(self): #Don't allow garbage after the duration #https://bitbucket.org/nielsenb/aniso8601/issues/9/durations-with-trailing-garbage-are-parsed with self.assertRaises(ValueError): parse_duration('P1Dasdfasdf') with self.assertRaises(ValueError): parse_duration('P0003-06-04T12:30:05.5asdfasdf')
def test_parse_duration_badstr(self): testtuples = ('PPPPPPPPPPPPPPPPPPPPPPPPPPPP', 'PTT', 'PX7DDDTX8888UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU' 'UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU8888888888888888H$H', 'P1Y2M3X.4D', 'P1Y2M3.4XD', 'P1Y2M3DT4H5M6XS', 'PT4H5M6X.2S', 'bad', '') for testtuple in testtuples: with self.assertRaises(ISOFormatError): parse_duration(testtuple, builder=None)
def test_parse_duration(self): resultduration = parse_duration('P1Y2M3DT4H54M6S') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) resultduration = parse_duration('P1Y2M3DT4H54M6.5S') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = parse_duration('P1Y2M3D') self.assertEqual(resultduration.days, 428) resultduration = parse_duration('PT4H54M6.5S') self.assertEqual(resultduration.days, 0) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = parse_duration('P1Y') self.assertEqual(resultduration.days, 365) resultduration = parse_duration('P1M') self.assertEqual(resultduration.days, 30) resultduration = parse_duration('P0003-06-04T12:30:05') self.assertEqual(resultduration.days, 1279) self.assertEqual(resultduration.seconds, 45005) self.assertEqual(resultduration.microseconds, 0) resultduration = parse_duration('P0003-06-04T12:30:05.5') self.assertEqual(resultduration.days, 1279) self.assertEqual(resultduration.seconds, 45005) self.assertEqual(resultduration.microseconds, 500000)
def test_parse_duration_badstr(self): testtuples = ( "PPPPPPPPPPPPPPPPPPPPPPPPPPPP", "PTT", "PX7DDDTX8888UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU8888888888888888H$H", "P1Y2M3X.4D", "P1Y2M3.4XD", "P1Y2M3DT4H5M6XS", "PT4H5M6X.2S", "bad", "", ) for testtuple in testtuples: with self.assertRaises(ISOFormatError): parse_duration(testtuple, builder=None)
def test_parse_duration_relative(self): resultduration = parse_duration('P1Y2M3DT4H54M6.5S', relative=True) self.assertEqual(resultduration.years, 1) self.assertEqual(resultduration.months, 2) self.assertEqual(resultduration.days, 3) self.assertEqual(resultduration.hours, 4) self.assertEqual(resultduration.minutes, 54) self.assertEqual(resultduration.seconds, 6.5) resultduration = parse_duration('P0003-06-04T12:30:05.5', relative=True) self.assertEqual(resultduration.years, 3) self.assertEqual(resultduration.months, 6) self.assertEqual(resultduration.days, 4) self.assertEqual(resultduration.hours, 12) self.assertEqual(resultduration.minutes, 30) self.assertEqual(resultduration.seconds, 5) self.assertEqual(resultduration.microseconds, 500000)
def test_parse_duration_mockbuilder(self): mockBuilder = mock.Mock() expectedargs = {'PnY': '1', 'PnM': '2', 'PnD': '3', 'TnH': '4', 'TnM': '54', 'TnS': '6'} mockBuilder.build_duration.return_value = expectedargs result = parse_duration('P1Y2M3DT4H54M6S', builder=mockBuilder) self.assertEqual(result, expectedargs) mockBuilder.build_duration.assert_called_once_with(**expectedargs)
def test_parse_duration_relative(self): resultduration = parse_duration('P1Y2M3DT4H54M6.5S', relative=True) self.assertEqual( resultduration, dateutil.relativedelta.relativedelta(years=1, months=2, days=3, hours=4, minutes=54, seconds=6.5)) resultduration = parse_duration('P0003-06-04T12:30:05.5', relative=True) self.assertEqual( resultduration, dateutil.relativedelta.relativedelta(years=3, months=6, days=4, hours=12, minutes=30, seconds=5, microseconds=500000)) #Make sure we truncate, not round #https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is resultduration = parse_duration('P0001-02-03T14:43:59.9999997', relative=True) self.assertEqual( resultduration, dateutil.relativedelta.relativedelta(years=1, months=2, days=3, hours=14, minutes=43, seconds=59, microseconds=999999))
def test_parse_duration_relative(self): with mock.patch.object(aniso8601.builder.RelativeTimeBuilder, 'build_duration') as mockBuildDuration: expectedargs = { 'PnY': '1', 'PnM': '2', 'PnD': '3', 'TnH': '4', 'TnM': '54', 'TnS': '6' } mockBuildDuration.return_value = expectedargs result = parse_duration('P1Y2M3DT4H54M6S', relative=True) self.assertEqual(result, expectedargs) mockBuildDuration.assert_called_once_with(**expectedargs)
def test_parse_duration_mockbuilder(self): mockBuilder = mock.Mock() expectedargs = { "PnY": "1", "PnM": "2", "PnD": "3", "TnH": "4", "TnM": "54", "TnS": "6", } mockBuilder.build_duration.return_value = expectedargs result = parse_duration("P1Y2M3DT4H54M6S", builder=mockBuilder) self.assertEqual(result, expectedargs) mockBuilder.build_duration.assert_called_once_with(**expectedargs)
def test_parse_duration_prescribed(self): resultduration = _parse_duration_prescribed('P1Y2M3DT4H54M6S', False) self.assertEqual( resultduration, datetime.timedelta(days=428, hours=4, minutes=54, seconds=6)) resultduration = _parse_duration_prescribed('P1Y2M3DT4H54M6.5S', False) self.assertEqual( resultduration, datetime.timedelta(days=428, hours=4, minutes=54, seconds=6.5)) resultduration = _parse_duration_prescribed('P1Y2M3DT4H54M6,5S', False) self.assertEqual( resultduration, datetime.timedelta(days=428, hours=4, minutes=54, seconds=6.5)) resultduration = _parse_duration_prescribed('PT4H54M6.5S', False) self.assertEqual(resultduration, datetime.timedelta(hours=4, minutes=54, seconds=6.5)) resultduration = _parse_duration_prescribed('PT4H54M6,5S', False) self.assertEqual(resultduration, datetime.timedelta(hours=4, minutes=54, seconds=6.5)) resultduration = _parse_duration_prescribed('P1Y2M3D', False) self.assertEqual(resultduration, datetime.timedelta(days=428)) resultduration = _parse_duration_prescribed('P1Y2M3.5D', False) self.assertEqual(resultduration, datetime.timedelta(days=428.5)) resultduration = _parse_duration_prescribed('P1Y2M3,5D', False) self.assertEqual(resultduration, datetime.timedelta(days=428.5)) resultduration = _parse_duration_prescribed('P1Y', False) self.assertEqual(resultduration, datetime.timedelta(days=365)) resultduration = _parse_duration_prescribed('P1.5Y', False) self.assertEqual(resultduration, datetime.timedelta(days=547.5)) resultduration = _parse_duration_prescribed('P1,5Y', False) self.assertEqual(resultduration, datetime.timedelta(days=547.5)) resultduration = _parse_duration_prescribed('P1M', False) self.assertEqual(resultduration, datetime.timedelta(days=30)) resultduration = _parse_duration_prescribed('P1.5M', False) self.assertEqual(resultduration, datetime.timedelta(days=45)) resultduration = _parse_duration_prescribed('P1,5M', False) self.assertEqual(resultduration, datetime.timedelta(days=45)) resultduration = _parse_duration_prescribed('P1W', False) self.assertEqual(resultduration, datetime.timedelta(days=7)) resultduration = _parse_duration_prescribed('P1.5W', False) self.assertEqual(resultduration, datetime.timedelta(days=10.5)) resultduration = _parse_duration_prescribed('P1,5W', False) self.assertEqual(resultduration, datetime.timedelta(days=10.5)) resultduration = _parse_duration_prescribed('P1D', False) self.assertEqual(resultduration, datetime.timedelta(days=1)) resultduration = _parse_duration_prescribed('P1.5D', False) self.assertEqual(resultduration, datetime.timedelta(days=1.5)) resultduration = _parse_duration_prescribed('P1,5D', False) self.assertEqual(resultduration, datetime.timedelta(days=1.5)) #Verify overflows self.assertEqual(parse_duration('PT36H'), parse_duration('P1DT12H'))
def test_parse_duration(self): resultduration = parse_duration('P1Y2M3DT4H54M6S') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) resultduration = parse_duration('P1Y2M3DT4H54M6.5S') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = parse_duration('P1Y2M3DT4H54M6,5S') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = parse_duration('P1Y2M3D') self.assertEqual(resultduration.days, 428) resultduration = parse_duration('P1Y2M3.5D') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 43200) resultduration = parse_duration('P1Y2M3,5D') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 43200) resultduration = parse_duration('PT4H54M6.5S') self.assertEqual(resultduration.days, 0) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = parse_duration('PT4H54M6,5S') self.assertEqual(resultduration.days, 0) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = parse_duration('P1Y') self.assertEqual(resultduration.days, 365) resultduration = parse_duration('P1.5Y') self.assertEqual(resultduration.days, 547) self.assertEqual(resultduration.seconds, 43200) resultduration = parse_duration('P1,5Y') self.assertEqual(resultduration.days, 547) self.assertEqual(resultduration.seconds, 43200) resultduration = parse_duration('P1M') self.assertEqual(resultduration.days, 30) resultduration = parse_duration('P1.5M') self.assertEqual(resultduration.days, 45) resultduration = parse_duration('P1,5M') self.assertEqual(resultduration.days, 45) resultduration = parse_duration('P1W') self.assertEqual(resultduration.days, 7) resultduration = parse_duration('P1.5W') self.assertEqual(resultduration.days, 10) self.assertEqual(resultduration.seconds, 43200) resultduration = parse_duration('P1,5W') self.assertEqual(resultduration.days, 10) self.assertEqual(resultduration.seconds, 43200) resultduration = parse_duration('P1D') self.assertEqual(resultduration.days, 1) resultduration = parse_duration('P1.5D') self.assertEqual(resultduration.days, 1) self.assertEqual(resultduration.seconds, 43200) resultduration = parse_duration('P1,5D') self.assertEqual(resultduration.days, 1) self.assertEqual(resultduration.seconds, 43200) resultduration = parse_duration('P0003-06-04T12:30:05') self.assertEqual(resultduration.days, 1279) self.assertEqual(resultduration.seconds, 45005) self.assertEqual(resultduration.microseconds, 0) resultduration = parse_duration('P0003-06-04T12:30:05.5') self.assertEqual(resultduration.days, 1279) self.assertEqual(resultduration.seconds, 45005) self.assertEqual(resultduration.microseconds, 500000) #Verify overflows self.assertEqual(parse_duration('PT36H'), parse_duration('P1DT12H'))
def test_parse_duration(self): testtuples = ( ( "P1Y2M3DT4H54M6S", { "PnY": "1", "PnM": "2", "PnD": "3", "TnH": "4", "TnM": "54", "TnS": "6", }, ), ( "P1Y2M3DT4H54M6.5S", { "PnY": "1", "PnM": "2", "PnD": "3", "TnH": "4", "TnM": "54", "TnS": "6.5", }, ), ( "P1Y2M3DT4H54M6,5S", { "PnY": "1", "PnM": "2", "PnD": "3", "TnH": "4", "TnM": "54", "TnS": "6.5", }, ), ("P1Y2M3D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3"}), ("P1Y2M3.5D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3.5"}), ("P1Y2M3,5D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3.5"}), ( "PT4H54M6.5S", { "PnY": None, "PnM": None, "PnD": None, "TnH": "4", "TnM": "54", "TnS": "6.5", }, ), ( "PT4H54M6,5S", { "PnY": None, "PnM": None, "PnD": None, "TnH": "4", "TnM": "54", "TnS": "6.5", }, ), ( "PT0.0000001S", { "PnY": None, "PnM": None, "PnD": None, "TnH": None, "TnM": None, "TnS": "0.0000001", }, ), ( "PT2.0000048S", { "PnY": None, "PnM": None, "PnD": None, "TnH": None, "TnM": None, "TnS": "2.0000048", }, ), ("P1Y", {"PnY": "1", "PnM": None, "PnW": None, "PnD": None}), ("P1.5Y", {"PnY": "1.5", "PnM": None, "PnW": None, "PnD": None}), ("P1,5Y", {"PnY": "1.5", "PnM": None, "PnW": None, "PnD": None}), ("P1M", {"PnY": None, "PnM": "1", "PnW": None, "PnD": None}), ("P1.5M", {"PnY": None, "PnM": "1.5", "PnW": None, "PnD": None}), ("P1,5M", {"PnY": None, "PnM": "1.5", "PnW": None, "PnD": None}), ("P1W", {"PnY": None, "PnM": None, "PnW": "1", "PnD": None}), ("P1.5W", {"PnY": None, "PnM": None, "PnW": "1.5", "PnD": None}), ("P1,5W", {"PnY": None, "PnM": None, "PnW": "1.5", "PnD": None}), ("P1D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1"}), ("P1.5D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1.5"}), ("P1,5D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1.5"}), ( "P0003-06-04T12:30:05", { "PnY": "0003", "PnM": "06", "PnD": "04", "TnH": "12", "TnM": "30", "TnS": "05", }, ), ( "P0003-06-04T12:30:05.5", { "PnY": "0003", "PnM": "06", "PnD": "04", "TnH": "12", "TnM": "30", "TnS": "05.5", }, ), ( "P0001-02-03T14:43:59.9999997", { "PnY": "0001", "PnM": "02", "PnD": "03", "TnH": "14", "TnM": "43", "TnS": "59.9999997", }, ), ) for testtuple in testtuples: with mock.patch.object( aniso8601.duration.PythonTimeBuilder, "build_duration" ) as mockBuildDuration: mockBuildDuration.return_value = testtuple[1] result = parse_duration(testtuple[0]) self.assertEqual(result, testtuple[1]) mockBuildDuration.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 test_parse_duration_badtype(self): testtuples = (None, 1, False, 1.234) for testtuple in testtuples: with self.assertRaises(ValueError): parse_duration(testtuple, builder=None)
def test_parse_duration_negative(self): with self.assertRaises(NegativeDurationError): parse_duration("P-1Y", builder=None) with self.assertRaises(NegativeDurationError): parse_duration("P-2M", builder=None) with self.assertRaises(NegativeDurationError): parse_duration("P-3D", builder=None) with self.assertRaises(NegativeDurationError): parse_duration("P-T4H", builder=None) with self.assertRaises(NegativeDurationError): parse_duration("P-T54M", builder=None) with self.assertRaises(NegativeDurationError): parse_duration("P-T6S", builder=None) with self.assertRaises(NegativeDurationError): parse_duration("P-7W", builder=None) with self.assertRaises(NegativeDurationError): parse_duration("P-1Y2M3DT4H54M6S", builder=None)
def test_parse_duration_prescribed(self): with self.assertRaises(ValueError): _parse_duration_prescribed('P1Y2M3DT4H5.1234M6.1234S') with self.assertRaises(ValueError): _parse_duration_prescribed('P1Y2M3DT4H5.1234M6S') resultduration = _parse_duration_prescribed('P1Y2M3DT4H54M6S') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) resultduration = _parse_duration_prescribed('P1Y2M3DT4H54M6.5S') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = _parse_duration_prescribed('P1Y2M3DT4H54M6,5S') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = _parse_duration_prescribed('P1Y2M3D') self.assertEqual(resultduration.days, 428) resultduration = _parse_duration_prescribed('P1Y2M3.5D') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1Y2M3,5D') self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('PT4H54M6.5S') self.assertEqual(resultduration.days, 0) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = _parse_duration_prescribed('PT4H54M6,5S') self.assertEqual(resultduration.days, 0) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = _parse_duration_prescribed('P1Y') self.assertEqual(resultduration.days, 365) resultduration = _parse_duration_prescribed('P1.5Y') self.assertEqual(resultduration.days, 547) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1,5Y') self.assertEqual(resultduration.days, 547) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1M') self.assertEqual(resultduration.days, 30) resultduration = _parse_duration_prescribed('P1.5M') self.assertEqual(resultduration.days, 45) resultduration = _parse_duration_prescribed('P1,5M') self.assertEqual(resultduration.days, 45) resultduration = _parse_duration_prescribed('P1W') self.assertEqual(resultduration.days, 7) resultduration = _parse_duration_prescribed('P1.5W') self.assertEqual(resultduration.days, 10) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1,5W') self.assertEqual(resultduration.days, 10) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1D') self.assertEqual(resultduration.days, 1) resultduration = _parse_duration_prescribed('P1.5D') self.assertEqual(resultduration.days, 1) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1,5D') self.assertEqual(resultduration.days, 1) self.assertEqual(resultduration.seconds, 43200) #Verify overflows self.assertEqual(parse_duration('PT36H'), parse_duration('P1DT12H'))
def test_parse_duration(self): testtuples = (('P1Y2M3DT4H54M6S', { 'PnY': '1', 'PnM': '2', 'PnD': '3', 'TnH': '4', 'TnM': '54', 'TnS': '6' }), ('P1Y2M3DT4H54M6.5S', { 'PnY': '1', 'PnM': '2', 'PnD': '3', 'TnH': '4', 'TnM': '54', 'TnS': '6.5' }), ('P1Y2M3DT4H54M6,5S', { 'PnY': '1', 'PnM': '2', 'PnD': '3', 'TnH': '4', 'TnM': '54', 'TnS': '6.5' }), ('P1Y2M3D', { 'PnY': '1', 'PnM': '2', 'PnW': None, 'PnD': '3' }), ('P1Y2M3.5D', { 'PnY': '1', 'PnM': '2', 'PnW': None, 'PnD': '3.5' }), ('P1Y2M3,5D', { 'PnY': '1', 'PnM': '2', 'PnW': None, 'PnD': '3.5' }), ('PT4H54M6.5S', { 'PnY': None, 'PnM': None, 'PnD': None, 'TnH': '4', 'TnM': '54', 'TnS': '6.5' }), ('PT4H54M6,5S', { 'PnY': None, 'PnM': None, 'PnD': None, 'TnH': '4', 'TnM': '54', 'TnS': '6.5' }), ('PT0.0000001S', { 'PnY': None, 'PnM': None, 'PnD': None, 'TnH': None, 'TnM': None, 'TnS': '0.0000001' }), ('PT2.0000048S', { 'PnY': None, 'PnM': None, 'PnD': None, 'TnH': None, 'TnM': None, 'TnS': '2.0000048' }), ('P1Y', { 'PnY': '1', 'PnM': None, 'PnW': None, 'PnD': None }), ('P1.5Y', { 'PnY': '1.5', 'PnM': None, 'PnW': None, 'PnD': None }), ('P1,5Y', { 'PnY': '1.5', 'PnM': None, 'PnW': None, 'PnD': None }), ('P1M', { 'PnY': None, 'PnM': '1', 'PnW': None, 'PnD': None }), ('P1.5M', { 'PnY': None, 'PnM': '1.5', 'PnW': None, 'PnD': None }), ('P1,5M', { 'PnY': None, 'PnM': '1.5', 'PnW': None, 'PnD': None }), ('P1W', { 'PnY': None, 'PnM': None, 'PnW': '1', 'PnD': None }), ('P1.5W', { 'PnY': None, 'PnM': None, 'PnW': '1.5', 'PnD': None }), ('P1,5W', { 'PnY': None, 'PnM': None, 'PnW': '1.5', 'PnD': None }), ('P1D', { 'PnY': None, 'PnM': None, 'PnW': None, 'PnD': '1' }), ('P1.5D', { 'PnY': None, 'PnM': None, 'PnW': None, 'PnD': '1.5' }), ('P1,5D', { 'PnY': None, 'PnM': None, 'PnW': None, 'PnD': '1.5' }), ('P0003-06-04T12:30:05', { 'PnY': '0003', 'PnM': '06', 'PnD': '04', 'TnH': '12', 'TnM': '30', 'TnS': '05' }), ('P0003-06-04T12:30:05.5', { 'PnY': '0003', 'PnM': '06', 'PnD': '04', 'TnH': '12', 'TnM': '30', 'TnS': '05.5' }), ('P0001-02-03T14:43:59.9999997', { 'PnY': '0001', 'PnM': '02', 'PnD': '03', 'TnH': '14', 'TnM': '43', 'TnS': '59.9999997' })) for testtuple in testtuples: with mock.patch.object(aniso8601.duration.PythonTimeBuilder, 'build_duration') as mockBuildDuration: mockBuildDuration.return_value = testtuple[1] result = parse_duration(testtuple[0]) self.assertEqual(result, testtuple[1]) mockBuildDuration.assert_called_once_with(**testtuple[1])
def test_parse_duration_weekcombination(self): with self.assertRaises(ISOFormatError): #Week designator cannot be combined with other time designators #https://bitbucket.org/nielsenb/aniso8601/issues/2/week-designators-should-not-be-combinable parse_duration('P1Y2W', builder=None)
def test_parse_duration_prescribed_relative_suffixgarbage(self): #Don't allow garbage after the duration #https://bitbucket.org/nielsenb/aniso8601/issues/9/durations-with-trailing-garbage-are-parsed with self.assertRaises(ValueError): parse_duration('P1Dasdfasdf', True)
def test_parse_duration_nop(self): with self.assertRaises(ValueError): #Duration must start with a P parse_duration('1Y2M3DT4H54M6S')
def test_parse_duration_badstr(self): testtuples = ('bad', '') for testtuple in testtuples: with self.assertRaises(ValueError): parse_duration(testtuple, builder=None)
def test_parse_duration(self): resultduration = parse_duration('P1Y2M3DT4H54M6S') self.assertEqual(resultduration, datetime.timedelta(days=428, seconds=17646)) resultduration = parse_duration('P1Y2M3DT4H54M6.5S') self.assertEqual(resultduration, datetime.timedelta(days=428, seconds=17646.5)) resultduration = parse_duration('P1Y2M3DT4H54M6,5S') self.assertEqual(resultduration, datetime.timedelta(days=428, seconds=17646.5)) resultduration = parse_duration('P1Y2M3D') self.assertEqual(resultduration, datetime.timedelta(days=428)) resultduration = parse_duration('P1Y2M3.5D') self.assertEqual(resultduration, datetime.timedelta(days=428.5)) resultduration = parse_duration('P1Y2M3,5D') self.assertEqual(resultduration, datetime.timedelta(days=428.5)) resultduration = parse_duration('PT4H54M6.5S') self.assertEqual(resultduration, datetime.timedelta(hours=4, minutes=54, seconds=6.5)) resultduration = parse_duration('PT4H54M6,5S') self.assertEqual(resultduration, datetime.timedelta(hours=4, minutes=54, seconds=6.5)) #Make sure we truncate, not round #https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is resultduration = parse_duration('PT0.0000001S') self.assertEqual(resultduration, datetime.timedelta(0)) resultduration = parse_duration('PT2.0000048S') self.assertEqual(resultduration, datetime.timedelta(seconds=2, microseconds=4)) resultduration = parse_duration('P1Y') self.assertEqual(resultduration, datetime.timedelta(days=365)) resultduration = parse_duration('P1.5Y') self.assertEqual(resultduration, datetime.timedelta(days=547.5)) resultduration = parse_duration('P1,5Y') self.assertEqual(resultduration, datetime.timedelta(days=547.5)) resultduration = parse_duration('P1M') self.assertEqual(resultduration, datetime.timedelta(days=30)) resultduration = parse_duration('P1.5M') self.assertEqual(resultduration, datetime.timedelta(days=45)) resultduration = parse_duration('P1,5M') self.assertEqual(resultduration, datetime.timedelta(days=45)) resultduration = parse_duration('P1W') self.assertEqual(resultduration, datetime.timedelta(days=7)) resultduration = parse_duration('P1.5W') self.assertEqual(resultduration, datetime.timedelta(days=10.5)) resultduration = parse_duration('P1,5W') self.assertEqual(resultduration, datetime.timedelta(days=10.5)) resultduration = parse_duration('P1D') self.assertEqual(resultduration, datetime.timedelta(days=1)) resultduration = parse_duration('P1.5D') self.assertEqual(resultduration, datetime.timedelta(days=1.5)) resultduration = parse_duration('P1,5D') self.assertEqual(resultduration, datetime.timedelta(days=1.5)) resultduration = parse_duration('P0003-06-04T12:30:05') self.assertEqual( resultduration, datetime.timedelta(days=1279, hours=12, minutes=30, seconds=5)) resultduration = parse_duration('P0003-06-04T12:30:05.5') self.assertEqual( resultduration, datetime.timedelta(days=1279, hours=12, minutes=30, seconds=5.5)) #Make sure we truncate, not round #https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is resultduration = parse_duration('P0001-02-03T14:43:59.9999997') self.assertEqual( resultduration, datetime.timedelta(days=428, hours=14, minutes=43, seconds=59, microseconds=999999)) #Verify overflows self.assertEqual(parse_duration('PT36H'), parse_duration('P1DT12H'))
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 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))
def test_parse_duration_nop(self): with self.assertRaises(ISOFormatError): #Duration must start with a P parse_duration('1Y2M3DT4H54M6S', builder=None)
def test_parse_duration_weekcombination(self): # Week designator cannot be combined with other time designators # https://bitbucket.org/nielsenb/aniso8601/issues/2/week-designators-should-not-be-combinable with self.assertRaises(ISOFormatError): parse_duration("P1Y2W", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P1M2W", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P2W3D", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P1Y2W3D", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P1M2W3D", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P1Y1M2W3D", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P7WT4H", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P7WT54M", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P7WT6S", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P7WT4H54M", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P7WT4H6S", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P7WT54M6S", builder=None) with self.assertRaises(ISOFormatError): parse_duration("P7WT4H54M6S", builder=None)
def test_parse_duration_negative(self): with self.assertRaises(NegativeDurationError): parse_duration('P-1Y', builder=None) with self.assertRaises(NegativeDurationError): parse_duration('P-2M', builder=None) with self.assertRaises(NegativeDurationError): parse_duration('P-3D', builder=None) with self.assertRaises(NegativeDurationError): parse_duration('P-T4H', builder=None) with self.assertRaises(NegativeDurationError): parse_duration('P-T54M', builder=None) with self.assertRaises(NegativeDurationError): parse_duration('P-T6S', builder=None) with self.assertRaises(NegativeDurationError): parse_duration('P-7W', builder=None) with self.assertRaises(NegativeDurationError): parse_duration('P-1Y2M3DT4H54M6S', builder=None)
def test_parse_duration_prescribed(self): with self.assertRaises(ValueError): _parse_duration_prescribed('P1Y2M3DT4H5.1234M6.1234S', False) with self.assertRaises(ValueError): _parse_duration_prescribed('P1Y2M3DT4H5.1234M6S', False) resultduration = _parse_duration_prescribed('P1Y2M3DT4H54M6S', False) self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) resultduration = _parse_duration_prescribed('P1Y2M3DT4H54M6.5S', False) self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = _parse_duration_prescribed('P1Y2M3DT4H54M6,5S', False) self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = _parse_duration_prescribed('P1Y2M3D', False) self.assertEqual(resultduration.days, 428) resultduration = _parse_duration_prescribed('P1Y2M3.5D', False) self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1Y2M3,5D', False) self.assertEqual(resultduration.days, 428) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('PT4H54M6.5S', False) self.assertEqual(resultduration.days, 0) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = _parse_duration_prescribed('PT4H54M6,5S', False) self.assertEqual(resultduration.days, 0) self.assertEqual(resultduration.seconds, 17646) self.assertEqual(resultduration.microseconds, 500000) resultduration = _parse_duration_prescribed('P1Y', False) self.assertEqual(resultduration.days, 365) resultduration = _parse_duration_prescribed('P1.5Y', False) self.assertEqual(resultduration.days, 547) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1,5Y', False) self.assertEqual(resultduration.days, 547) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1M', False) self.assertEqual(resultduration.days, 30) resultduration = _parse_duration_prescribed('P1.5M', False) self.assertEqual(resultduration.days, 45) resultduration = _parse_duration_prescribed('P1,5M', False) self.assertEqual(resultduration.days, 45) resultduration = _parse_duration_prescribed('P1W', False) self.assertEqual(resultduration.days, 7) resultduration = _parse_duration_prescribed('P1.5W', False) self.assertEqual(resultduration.days, 10) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1,5W', False) self.assertEqual(resultduration.days, 10) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1D', False) self.assertEqual(resultduration.days, 1) resultduration = _parse_duration_prescribed('P1.5D', False) self.assertEqual(resultduration.days, 1) self.assertEqual(resultduration.seconds, 43200) resultduration = _parse_duration_prescribed('P1,5D', False) self.assertEqual(resultduration.days, 1) self.assertEqual(resultduration.seconds, 43200) #Verify overflows self.assertEqual(parse_duration('PT36H', False), parse_duration('P1DT12H', False))
def test_parse_duration_outoforder(self): #Ensure durations are required to be in the correct order #https://bitbucket.org/nielsenb/aniso8601/issues/7/durations-with-time-components-before-t #https://bitbucket.org/nielsenb/aniso8601/issues/8/durations-with-components-in-wrong-order with self.assertRaises(ISOFormatError): parse_duration('P1S', builder=None) with self.assertRaises(ISOFormatError): parse_duration('P1D1S', builder=None) with self.assertRaises(ISOFormatError): parse_duration('P1H1M', builder=None) with self.assertRaises(ISOFormatError): parse_duration('1Y2M3D1SPT1M', builder=None) with self.assertRaises(ISOFormatError): parse_duration('P1Y2M3D2MT1S', builder=None) with self.assertRaises(ISOFormatError): parse_duration('P2M3D1ST1Y1M', builder=None) with self.assertRaises(ISOFormatError): parse_duration('P1Y2M2MT3D1S', builder=None) with self.assertRaises(ISOFormatError): parse_duration('P1D1Y1M', builder=None) with self.assertRaises(ISOFormatError): parse_duration('PT1S1H', builder=None)