Exemple #1
0
    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)
Exemple #3
0
    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)
Exemple #5
0
    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)
Exemple #7
0
    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)
Exemple #9
0
    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))
Exemple #10
0
    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)
Exemple #12
0
    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])
Exemple #15
0
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))
Exemple #16
0
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)
Exemple #17
0
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)
Exemple #18
0
    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'))
Exemple #21
0
    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])
Exemple #22
0
 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)
Exemple #23
0
 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)
Exemple #24
0
 def test_parse_duration_nop(self):
     with self.assertRaises(ValueError):
         #Duration must start with a P
         parse_duration('1Y2M3DT4H54M6S')
Exemple #25
0
    def test_parse_duration_badstr(self):
        testtuples = ('bad', '')

        for testtuple in testtuples:
            with self.assertRaises(ValueError):
                parse_duration(testtuple, builder=None)
Exemple #26
0
    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'))
Exemple #27
0
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)
Exemple #28
0
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))
Exemple #29
0
 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)
Exemple #31
0
    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)
Exemple #32
0
    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))
Exemple #33
0
    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)
Exemple #34
0
    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'))