You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1711 lines
60 KiB
1711 lines
60 KiB
2 years ago
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
# Copyright (c) 2021, Brandon Nielsen
|
||
|
# All rights reserved.
|
||
|
#
|
||
|
# This software may be modified and distributed under the terms
|
||
|
# of the BSD license. See the LICENSE file for details.
|
||
|
|
||
|
import datetime
|
||
|
import unittest
|
||
|
|
||
|
from aniso8601 import compat
|
||
|
from aniso8601.builders import (
|
||
|
DatetimeTuple,
|
||
|
DateTuple,
|
||
|
DurationTuple,
|
||
|
IntervalTuple,
|
||
|
Limit,
|
||
|
TimeTuple,
|
||
|
TimezoneTuple,
|
||
|
)
|
||
|
from aniso8601.builders.python import (
|
||
|
FractionalComponent,
|
||
|
PythonTimeBuilder,
|
||
|
_cast_to_fractional_component,
|
||
|
fractional_range_check,
|
||
|
year_range_check,
|
||
|
)
|
||
|
from aniso8601.exceptions import (
|
||
|
DayOutOfBoundsError,
|
||
|
HoursOutOfBoundsError,
|
||
|
ISOFormatError,
|
||
|
LeapSecondError,
|
||
|
MidnightBoundsError,
|
||
|
MinutesOutOfBoundsError,
|
||
|
MonthOutOfBoundsError,
|
||
|
SecondsOutOfBoundsError,
|
||
|
WeekOutOfBoundsError,
|
||
|
YearOutOfBoundsError,
|
||
|
)
|
||
|
from aniso8601.utcoffset import UTCOffset
|
||
|
|
||
|
|
||
|
class TestPythonTimeBuilder_UtiltyFunctions(unittest.TestCase):
|
||
|
def test_year_range_check(self):
|
||
|
yearlimit = Limit(
|
||
|
"Invalid year string.",
|
||
|
0000,
|
||
|
9999,
|
||
|
YearOutOfBoundsError,
|
||
|
"Year must be between 1..9999.",
|
||
|
None,
|
||
|
)
|
||
|
|
||
|
self.assertEqual(year_range_check("1", yearlimit), 1000)
|
||
|
|
||
|
def test_fractional_range_check(self):
|
||
|
limit = Limit(
|
||
|
"Invalid string.", -1, 1, ValueError, "Value must be between -1..1.", None
|
||
|
)
|
||
|
|
||
|
self.assertEqual(fractional_range_check(10, "1", limit), 1)
|
||
|
self.assertEqual(fractional_range_check(10, "-1", limit), -1)
|
||
|
self.assertEqual(
|
||
|
fractional_range_check(10, "0.1", limit), FractionalComponent(0, 1)
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
fractional_range_check(10, "-0.1", limit), FractionalComponent(-0, 1)
|
||
|
)
|
||
|
|
||
|
with self.assertRaises(ValueError):
|
||
|
fractional_range_check(10, "1.1", limit)
|
||
|
|
||
|
with self.assertRaises(ValueError):
|
||
|
fractional_range_check(10, "-1.1", limit)
|
||
|
|
||
|
def test_cast_to_fractional_component(self):
|
||
|
self.assertEqual(
|
||
|
_cast_to_fractional_component(10, "1.1"), FractionalComponent(1, 1)
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
_cast_to_fractional_component(10, "-1.1"), FractionalComponent(-1, 1)
|
||
|
)
|
||
|
|
||
|
self.assertEqual(
|
||
|
_cast_to_fractional_component(100, "1.1"), FractionalComponent(1, 10)
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
_cast_to_fractional_component(100, "-1.1"), FractionalComponent(-1, 10)
|
||
|
)
|
||
|
|
||
|
|
||
|
class TestPythonTimeBuilder(unittest.TestCase):
|
||
|
def test_build_date(self):
|
||
|
testtuples = (
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "2013",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(2013, 1, 1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "0001",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(1, 1, 1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "1900",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(1900, 1, 1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "1981",
|
||
|
"MM": "04",
|
||
|
"DD": "05",
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(1981, 4, 5),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "1981",
|
||
|
"MM": "04",
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(1981, 4, 1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "1981",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": "095",
|
||
|
},
|
||
|
datetime.date(1981, 4, 5),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "1981",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": "365",
|
||
|
},
|
||
|
datetime.date(1981, 12, 31),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "1980",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": "366",
|
||
|
},
|
||
|
datetime.date(1980, 12, 31),
|
||
|
),
|
||
|
# Make sure we shift in zeros
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "1",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(1000, 1, 1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "12",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(1200, 1, 1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "123",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": None,
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(1230, 1, 1),
|
||
|
),
|
||
|
)
|
||
|
|
||
|
for testtuple in testtuples:
|
||
|
result = PythonTimeBuilder.build_date(**testtuple[0])
|
||
|
self.assertEqual(result, testtuple[1])
|
||
|
|
||
|
# Test weekday
|
||
|
testtuples = (
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "2004",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": "53",
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(2004, 12, 27),
|
||
|
0,
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "2009",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": "01",
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(2008, 12, 29),
|
||
|
0,
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "2010",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": "01",
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(2010, 1, 4),
|
||
|
0,
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "2009",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": "53",
|
||
|
"D": None,
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(2009, 12, 28),
|
||
|
0,
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "2009",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": "01",
|
||
|
"D": "1",
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(2008, 12, 29),
|
||
|
0,
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "2009",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": "53",
|
||
|
"D": "7",
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(2010, 1, 3),
|
||
|
6,
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "2010",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": "01",
|
||
|
"D": "1",
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(2010, 1, 4),
|
||
|
0,
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"YYYY": "2004",
|
||
|
"MM": None,
|
||
|
"DD": None,
|
||
|
"Www": "53",
|
||
|
"D": "6",
|
||
|
"DDD": None,
|
||
|
},
|
||
|
datetime.date(2005, 1, 1),
|
||
|
5,
|
||
|
),
|
||
|
)
|
||
|
|
||
|
for testtuple in testtuples:
|
||
|
result = PythonTimeBuilder.build_date(**testtuple[0])
|
||
|
self.assertEqual(result, testtuple[1])
|
||
|
self.assertEqual(result.weekday(), testtuple[2])
|
||
|
|
||
|
def test_build_time(self):
|
||
|
testtuples = (
|
||
|
({}, datetime.time()),
|
||
|
({"hh": "12.5"}, datetime.time(hour=12, minute=30)),
|
||
|
(
|
||
|
{"hh": "23.99999999997"},
|
||
|
datetime.time(hour=23, minute=59, second=59, microsecond=999999),
|
||
|
),
|
||
|
({"hh": "1", "mm": "23"}, datetime.time(hour=1, minute=23)),
|
||
|
(
|
||
|
{"hh": "1", "mm": "23.4567"},
|
||
|
datetime.time(hour=1, minute=23, second=27, microsecond=402000),
|
||
|
),
|
||
|
(
|
||
|
{"hh": "14", "mm": "43.999999997"},
|
||
|
datetime.time(hour=14, minute=43, second=59, microsecond=999999),
|
||
|
),
|
||
|
(
|
||
|
{"hh": "1", "mm": "23", "ss": "45"},
|
||
|
datetime.time(hour=1, minute=23, second=45),
|
||
|
),
|
||
|
(
|
||
|
{"hh": "23", "mm": "21", "ss": "28.512400"},
|
||
|
datetime.time(hour=23, minute=21, second=28, microsecond=512400),
|
||
|
),
|
||
|
(
|
||
|
{"hh": "01", "mm": "03", "ss": "11.858714"},
|
||
|
datetime.time(hour=1, minute=3, second=11, microsecond=858714),
|
||
|
),
|
||
|
(
|
||
|
{"hh": "14", "mm": "43", "ss": "59.9999997"},
|
||
|
datetime.time(hour=14, minute=43, second=59, microsecond=999999),
|
||
|
),
|
||
|
({"hh": "24"}, datetime.time(hour=0)),
|
||
|
({"hh": "24", "mm": "00"}, datetime.time(hour=0)),
|
||
|
({"hh": "24", "mm": "00", "ss": "00"}, datetime.time(hour=0)),
|
||
|
(
|
||
|
{"tz": TimezoneTuple(False, None, "00", "00", "UTC")},
|
||
|
datetime.time(tzinfo=UTCOffset(name="UTC", minutes=0)),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"hh": "23",
|
||
|
"mm": "21",
|
||
|
"ss": "28.512400",
|
||
|
"tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
|
||
|
},
|
||
|
datetime.time(
|
||
|
hour=23,
|
||
|
minute=21,
|
||
|
second=28,
|
||
|
microsecond=512400,
|
||
|
tzinfo=UTCOffset(name="+00:00", minutes=0),
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"hh": "1",
|
||
|
"mm": "23",
|
||
|
"tz": TimezoneTuple(False, None, "01", "00", "+1"),
|
||
|
},
|
||
|
datetime.time(
|
||
|
hour=1, minute=23, tzinfo=UTCOffset(name="+1", minutes=60)
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"hh": "1",
|
||
|
"mm": "23.4567",
|
||
|
"tz": TimezoneTuple(True, None, "01", "00", "-1"),
|
||
|
},
|
||
|
datetime.time(
|
||
|
hour=1,
|
||
|
minute=23,
|
||
|
second=27,
|
||
|
microsecond=402000,
|
||
|
tzinfo=UTCOffset(name="-1", minutes=-60),
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"hh": "23",
|
||
|
"mm": "21",
|
||
|
"ss": "28.512400",
|
||
|
"tz": TimezoneTuple(False, None, "01", "30", "+1:30"),
|
||
|
},
|
||
|
datetime.time(
|
||
|
hour=23,
|
||
|
minute=21,
|
||
|
second=28,
|
||
|
microsecond=512400,
|
||
|
tzinfo=UTCOffset(name="+1:30", minutes=90),
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"hh": "23",
|
||
|
"mm": "21",
|
||
|
"ss": "28.512400",
|
||
|
"tz": TimezoneTuple(False, None, "11", "15", "+11:15"),
|
||
|
},
|
||
|
datetime.time(
|
||
|
hour=23,
|
||
|
minute=21,
|
||
|
second=28,
|
||
|
microsecond=512400,
|
||
|
tzinfo=UTCOffset(name="+11:15", minutes=675),
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"hh": "23",
|
||
|
"mm": "21",
|
||
|
"ss": "28.512400",
|
||
|
"tz": TimezoneTuple(False, None, "12", "34", "+12:34"),
|
||
|
},
|
||
|
datetime.time(
|
||
|
hour=23,
|
||
|
minute=21,
|
||
|
second=28,
|
||
|
microsecond=512400,
|
||
|
tzinfo=UTCOffset(name="+12:34", minutes=754),
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"hh": "23",
|
||
|
"mm": "21",
|
||
|
"ss": "28.512400",
|
||
|
"tz": TimezoneTuple(False, None, "00", "00", "UTC"),
|
||
|
},
|
||
|
datetime.time(
|
||
|
hour=23,
|
||
|
minute=21,
|
||
|
second=28,
|
||
|
microsecond=512400,
|
||
|
tzinfo=UTCOffset(name="UTC", minutes=0),
|
||
|
),
|
||
|
),
|
||
|
# Make sure we truncate, not round
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/21/sub-microsecond-precision-is-lost-when
|
||
|
(
|
||
|
{"hh": "14.9999999999999999"},
|
||
|
datetime.time(hour=14, minute=59, second=59, microsecond=999999),
|
||
|
),
|
||
|
({"mm": "0.00000000999"}, datetime.time()),
|
||
|
({"mm": "0.0000000999"}, datetime.time(microsecond=5)),
|
||
|
({"ss": "0.0000001"}, datetime.time()),
|
||
|
({"ss": "2.0000048"}, datetime.time(second=2, microsecond=4)),
|
||
|
)
|
||
|
|
||
|
for testtuple in testtuples:
|
||
|
result = PythonTimeBuilder.build_time(**testtuple[0])
|
||
|
self.assertEqual(result, testtuple[1])
|
||
|
|
||
|
def test_build_datetime(self):
|
||
|
testtuples = (
|
||
|
(
|
||
|
(
|
||
|
DateTuple("2019", "06", "05", None, None, None),
|
||
|
TimeTuple("01", "03", "11.858714", None),
|
||
|
),
|
||
|
datetime.datetime(
|
||
|
2019, 6, 5, hour=1, minute=3, second=11, microsecond=858714
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
(
|
||
|
DateTuple("1234", "02", "03", None, None, None),
|
||
|
TimeTuple("23", "21", "28.512400", None),
|
||
|
),
|
||
|
datetime.datetime(
|
||
|
1234, 2, 3, hour=23, minute=21, second=28, microsecond=512400
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
TimeTuple(
|
||
|
"23",
|
||
|
"21",
|
||
|
"28.512400",
|
||
|
TimezoneTuple(False, None, "11", "15", "+11:15"),
|
||
|
),
|
||
|
),
|
||
|
datetime.datetime(
|
||
|
1981,
|
||
|
4,
|
||
|
5,
|
||
|
hour=23,
|
||
|
minute=21,
|
||
|
second=28,
|
||
|
microsecond=512400,
|
||
|
tzinfo=UTCOffset(name="+11:15", minutes=675),
|
||
|
),
|
||
|
),
|
||
|
)
|
||
|
|
||
|
for testtuple in testtuples:
|
||
|
result = PythonTimeBuilder.build_datetime(*testtuple[0])
|
||
|
self.assertEqual(result, testtuple[1])
|
||
|
|
||
|
def test_build_duration(self):
|
||
|
testtuples = (
|
||
|
(
|
||
|
{
|
||
|
"PnY": "1",
|
||
|
"PnM": "2",
|
||
|
"PnD": "3",
|
||
|
"TnH": "4",
|
||
|
"TnM": "54",
|
||
|
"TnS": "6",
|
||
|
},
|
||
|
datetime.timedelta(days=428, hours=4, minutes=54, seconds=6),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"PnY": "1",
|
||
|
"PnM": "2",
|
||
|
"PnD": "3",
|
||
|
"TnH": "4",
|
||
|
"TnM": "54",
|
||
|
"TnS": "6.5",
|
||
|
},
|
||
|
datetime.timedelta(days=428, hours=4, minutes=54, seconds=6.5),
|
||
|
),
|
||
|
({"PnY": "1", "PnM": "2", "PnD": "3"}, datetime.timedelta(days=428)),
|
||
|
({"PnY": "1", "PnM": "2", "PnD": "3.5"}, datetime.timedelta(days=428.5)),
|
||
|
(
|
||
|
{"TnH": "4", "TnM": "54", "TnS": "6.5"},
|
||
|
datetime.timedelta(hours=4, minutes=54, seconds=6.5),
|
||
|
),
|
||
|
(
|
||
|
{"TnH": "1", "TnM": "3", "TnS": "11.858714"},
|
||
|
datetime.timedelta(hours=1, minutes=3, seconds=11, microseconds=858714),
|
||
|
),
|
||
|
(
|
||
|
{"TnH": "4", "TnM": "54", "TnS": "28.512400"},
|
||
|
datetime.timedelta(
|
||
|
hours=4, minutes=54, seconds=28, microseconds=512400
|
||
|
),
|
||
|
),
|
||
|
# Make sure we truncate, not round
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/21/sub-microsecond-precision-is-lost-when
|
||
|
(
|
||
|
{"PnY": "1999.9999999999999999"},
|
||
|
datetime.timedelta(days=729999, seconds=86399, microseconds=999999),
|
||
|
),
|
||
|
(
|
||
|
{"PnM": "1.9999999999999999"},
|
||
|
datetime.timedelta(
|
||
|
days=59, hours=23, minutes=59, seconds=59, microseconds=999999
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{"PnW": "1.9999999999999999"},
|
||
|
datetime.timedelta(
|
||
|
days=13, hours=23, minutes=59, seconds=59, microseconds=999999
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{"PnD": "1.9999999999999999"},
|
||
|
datetime.timedelta(
|
||
|
days=1, hours=23, minutes=59, seconds=59, microseconds=999999
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{"TnH": "14.9999999999999999"},
|
||
|
datetime.timedelta(
|
||
|
hours=14, minutes=59, seconds=59, microseconds=999999
|
||
|
),
|
||
|
),
|
||
|
({"TnM": "0.00000000999"}, datetime.timedelta(0)),
|
||
|
({"TnM": "0.0000000999"}, datetime.timedelta(microseconds=5)),
|
||
|
({"TnS": "0.0000001"}, datetime.timedelta(0)),
|
||
|
({"TnS": "2.0000048"}, datetime.timedelta(seconds=2, microseconds=4)),
|
||
|
({"PnY": "1"}, datetime.timedelta(days=365)),
|
||
|
({"PnY": "1.5"}, datetime.timedelta(days=547.5)),
|
||
|
({"PnM": "1"}, datetime.timedelta(days=30)),
|
||
|
({"PnM": "1.5"}, datetime.timedelta(days=45)),
|
||
|
({"PnW": "1"}, datetime.timedelta(days=7)),
|
||
|
({"PnW": "1.5"}, datetime.timedelta(days=10.5)),
|
||
|
({"PnD": "1"}, datetime.timedelta(days=1)),
|
||
|
({"PnD": "1.5"}, datetime.timedelta(days=1.5)),
|
||
|
(
|
||
|
{
|
||
|
"PnY": "0003",
|
||
|
"PnM": "06",
|
||
|
"PnD": "04",
|
||
|
"TnH": "12",
|
||
|
"TnM": "30",
|
||
|
"TnS": "05",
|
||
|
},
|
||
|
datetime.timedelta(days=1279, hours=12, minutes=30, seconds=5),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"PnY": "0003",
|
||
|
"PnM": "06",
|
||
|
"PnD": "04",
|
||
|
"TnH": "12",
|
||
|
"TnM": "30",
|
||
|
"TnS": "05.5",
|
||
|
},
|
||
|
datetime.timedelta(days=1279, hours=12, minutes=30, seconds=5.5),
|
||
|
),
|
||
|
# Test timedelta limit
|
||
|
(
|
||
|
{"PnD": "999999999", "TnH": "23", "TnM": "59", "TnS": "59.999999"},
|
||
|
datetime.timedelta.max,
|
||
|
),
|
||
|
# Make sure we truncate, not round
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
|
||
|
(
|
||
|
{
|
||
|
"PnY": "0001",
|
||
|
"PnM": "02",
|
||
|
"PnD": "03",
|
||
|
"TnH": "14",
|
||
|
"TnM": "43",
|
||
|
"TnS": "59.9999997",
|
||
|
},
|
||
|
datetime.timedelta(
|
||
|
days=428, hours=14, minutes=43, seconds=59, microseconds=999999
|
||
|
),
|
||
|
),
|
||
|
# Verify overflows
|
||
|
({"TnH": "36"}, datetime.timedelta(days=1, hours=12)),
|
||
|
)
|
||
|
|
||
|
for testtuple in testtuples:
|
||
|
result = PythonTimeBuilder.build_duration(**testtuple[0])
|
||
|
self.assertEqual(result, testtuple[1])
|
||
|
|
||
|
def test_build_interval(self):
|
||
|
testtuples = (
|
||
|
(
|
||
|
{
|
||
|
"end": DatetimeTuple(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
"duration": DurationTuple(None, "1", None, None, None, None, None),
|
||
|
},
|
||
|
datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1),
|
||
|
datetime.datetime(year=1981, month=3, day=6, hour=1, minute=1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("1981", "04", "05", None, None, None),
|
||
|
"duration": DurationTuple(None, "1", None, None, None, None, None),
|
||
|
},
|
||
|
datetime.date(year=1981, month=4, day=5),
|
||
|
datetime.date(year=1981, month=3, day=6),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("2018", "03", "06", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
"1.5", None, None, None, None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2018, month=3, day=6),
|
||
|
datetime.datetime(year=2016, month=9, day=4, hour=12),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("2014", "11", "12", None, None, None),
|
||
|
"duration": DurationTuple(None, None, None, None, "1", None, None),
|
||
|
},
|
||
|
datetime.date(year=2014, month=11, day=12),
|
||
|
datetime.datetime(year=2014, month=11, day=11, hour=23),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("2014", "11", "12", None, None, None),
|
||
|
"duration": DurationTuple(None, None, None, None, "4", "54", "6.5"),
|
||
|
},
|
||
|
datetime.date(year=2014, month=11, day=12),
|
||
|
datetime.datetime(
|
||
|
year=2014,
|
||
|
month=11,
|
||
|
day=11,
|
||
|
hour=19,
|
||
|
minute=5,
|
||
|
second=53,
|
||
|
microsecond=500000,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DatetimeTuple(
|
||
|
DateTuple("2050", "03", "01", None, None, None),
|
||
|
TimeTuple(
|
||
|
"13",
|
||
|
"00",
|
||
|
"00",
|
||
|
TimezoneTuple(False, True, None, None, "Z"),
|
||
|
),
|
||
|
),
|
||
|
"duration": DurationTuple(None, None, None, None, "10", None, None),
|
||
|
},
|
||
|
datetime.datetime(
|
||
|
year=2050,
|
||
|
month=3,
|
||
|
day=1,
|
||
|
hour=13,
|
||
|
tzinfo=UTCOffset(name="UTC", minutes=0),
|
||
|
),
|
||
|
datetime.datetime(
|
||
|
year=2050,
|
||
|
month=3,
|
||
|
day=1,
|
||
|
hour=3,
|
||
|
tzinfo=UTCOffset(name="UTC", minutes=0),
|
||
|
),
|
||
|
),
|
||
|
# Make sure we truncate, not round
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/21/sub-microsecond-precision-is-lost-when
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("2000", "01", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
"1999.9999999999999999", None, None, None, None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2000, month=1, day=1),
|
||
|
datetime.datetime(
|
||
|
year=1, month=4, day=30, hour=0, minute=0, second=0, microsecond=1
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("1989", "03", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, "1.9999999999999999", None, None, None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=1989, month=3, day=1),
|
||
|
datetime.datetime(
|
||
|
year=1988,
|
||
|
month=12,
|
||
|
day=31,
|
||
|
hour=0,
|
||
|
minute=0,
|
||
|
second=0,
|
||
|
microsecond=1,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("1989", "03", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, "1.9999999999999999", None, None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=1989, month=3, day=1),
|
||
|
datetime.datetime(
|
||
|
year=1989,
|
||
|
month=2,
|
||
|
day=15,
|
||
|
hour=0,
|
||
|
minute=0,
|
||
|
second=0,
|
||
|
microsecond=1,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("1989", "03", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, "1.9999999999999999", None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=1989, month=3, day=1),
|
||
|
datetime.datetime(
|
||
|
year=1989,
|
||
|
month=2,
|
||
|
day=27,
|
||
|
hour=0,
|
||
|
minute=0,
|
||
|
second=0,
|
||
|
microsecond=1,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("2001", "01", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, "14.9999999999999999", None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2001, month=1, day=1),
|
||
|
datetime.datetime(
|
||
|
year=2000,
|
||
|
month=12,
|
||
|
day=31,
|
||
|
hour=9,
|
||
|
minute=0,
|
||
|
second=0,
|
||
|
microsecond=1,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("2001", "01", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, None, "0.00000000999", None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2001, month=1, day=1),
|
||
|
datetime.datetime(year=2001, month=1, day=1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("2001", "01", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, None, "0.0000000999", None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2001, month=1, day=1),
|
||
|
datetime.datetime(
|
||
|
year=2000,
|
||
|
month=12,
|
||
|
day=31,
|
||
|
hour=23,
|
||
|
minute=59,
|
||
|
second=59,
|
||
|
microsecond=999995,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("2018", "03", "06", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, None, None, "0.0000001"
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2018, month=3, day=6),
|
||
|
datetime.datetime(year=2018, month=3, day=6),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"end": DateTuple("2018", "03", "06", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, None, None, "2.0000048"
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2018, month=3, day=6),
|
||
|
datetime.datetime(
|
||
|
year=2018,
|
||
|
month=3,
|
||
|
day=5,
|
||
|
hour=23,
|
||
|
minute=59,
|
||
|
second=57,
|
||
|
microsecond=999996,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
"duration": DurationTuple(None, "1", None, "1", None, "1", None),
|
||
|
},
|
||
|
datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1),
|
||
|
datetime.datetime(year=1981, month=5, day=6, hour=1, minute=2),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("1981", "04", "05", None, None, None),
|
||
|
"duration": DurationTuple(None, "1", None, "1", None, None, None),
|
||
|
},
|
||
|
datetime.date(year=1981, month=4, day=5),
|
||
|
datetime.date(year=1981, month=5, day=6),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2018", "03", "06", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, "2.5", None, None, None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2018, month=3, day=6),
|
||
|
datetime.date(year=2018, month=5, day=20),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2014", "11", "12", None, None, None),
|
||
|
"duration": DurationTuple(None, None, None, None, "1", None, None),
|
||
|
},
|
||
|
datetime.date(year=2014, month=11, day=12),
|
||
|
datetime.datetime(year=2014, month=11, day=12, hour=1, minute=0),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2014", "11", "12", None, None, None),
|
||
|
"duration": DurationTuple(None, None, None, None, "4", "54", "6.5"),
|
||
|
},
|
||
|
datetime.date(year=2014, month=11, day=12),
|
||
|
datetime.datetime(
|
||
|
year=2014,
|
||
|
month=11,
|
||
|
day=12,
|
||
|
hour=4,
|
||
|
minute=54,
|
||
|
second=6,
|
||
|
microsecond=500000,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("2050", "03", "01", None, None, None),
|
||
|
TimeTuple(
|
||
|
"13",
|
||
|
"00",
|
||
|
"00",
|
||
|
TimezoneTuple(False, True, None, None, "Z"),
|
||
|
),
|
||
|
),
|
||
|
"duration": DurationTuple(None, None, None, None, "10", None, None),
|
||
|
},
|
||
|
datetime.datetime(
|
||
|
year=2050,
|
||
|
month=3,
|
||
|
day=1,
|
||
|
hour=13,
|
||
|
tzinfo=UTCOffset(name="UTC", minutes=0),
|
||
|
),
|
||
|
datetime.datetime(
|
||
|
year=2050,
|
||
|
month=3,
|
||
|
day=1,
|
||
|
hour=23,
|
||
|
tzinfo=UTCOffset(name="UTC", minutes=0),
|
||
|
),
|
||
|
),
|
||
|
# Make sure we truncate, not round
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("0001", "01", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
"1999.9999999999999999", None, None, None, None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=1, month=1, day=1),
|
||
|
datetime.datetime(
|
||
|
year=1999,
|
||
|
month=9,
|
||
|
day=3,
|
||
|
hour=23,
|
||
|
minute=59,
|
||
|
second=59,
|
||
|
microsecond=999999,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("1989", "03", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, "1.9999999999999999", None, None, None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=1989, month=3, day=1),
|
||
|
datetime.datetime(
|
||
|
year=1989,
|
||
|
month=4,
|
||
|
day=29,
|
||
|
hour=23,
|
||
|
minute=59,
|
||
|
second=59,
|
||
|
microsecond=999999,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("1989", "03", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, "1.9999999999999999", None, None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=1989, month=3, day=1),
|
||
|
datetime.datetime(
|
||
|
year=1989,
|
||
|
month=3,
|
||
|
day=14,
|
||
|
hour=23,
|
||
|
minute=59,
|
||
|
second=59,
|
||
|
microsecond=999999,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("1989", "03", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, "1.9999999999999999", None, None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=1989, month=3, day=1),
|
||
|
datetime.datetime(
|
||
|
year=1989,
|
||
|
month=3,
|
||
|
day=2,
|
||
|
hour=23,
|
||
|
minute=59,
|
||
|
second=59,
|
||
|
microsecond=999999,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2001", "01", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, "14.9999999999999999", None, None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2001, month=1, day=1),
|
||
|
datetime.datetime(
|
||
|
year=2001,
|
||
|
month=1,
|
||
|
day=1,
|
||
|
hour=14,
|
||
|
minute=59,
|
||
|
second=59,
|
||
|
microsecond=999999,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2001", "01", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, None, "0.00000000999", None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2001, month=1, day=1),
|
||
|
datetime.datetime(year=2001, month=1, day=1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2001", "01", "01", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, None, "0.0000000999", None
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2001, month=1, day=1),
|
||
|
datetime.datetime(
|
||
|
year=2001, month=1, day=1, hour=0, minute=0, second=0, microsecond=5
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2018", "03", "06", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, None, None, "0.0000001"
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2018, month=3, day=6),
|
||
|
datetime.datetime(year=2018, month=3, day=6),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2018", "03", "06", None, None, None),
|
||
|
"duration": DurationTuple(
|
||
|
None, None, None, None, None, None, "2.0000048"
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=2018, month=3, day=6),
|
||
|
datetime.datetime(
|
||
|
year=2018, month=3, day=6, hour=0, minute=0, second=2, microsecond=4
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("1980", "03", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
"end": DatetimeTuple(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
},
|
||
|
datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1),
|
||
|
datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("1980", "03", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
"end": DateTuple("1981", "04", "05", None, None, None),
|
||
|
},
|
||
|
datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1),
|
||
|
datetime.date(year=1981, month=4, day=5),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("1980", "03", "05", None, None, None),
|
||
|
"end": DatetimeTuple(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
},
|
||
|
datetime.date(year=1980, month=3, day=5),
|
||
|
datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("1980", "03", "05", None, None, None),
|
||
|
"end": DateTuple("1981", "04", "05", None, None, None),
|
||
|
},
|
||
|
datetime.date(year=1980, month=3, day=5),
|
||
|
datetime.date(year=1981, month=4, day=5),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("1981", "04", "05", None, None, None),
|
||
|
"end": DateTuple("1980", "03", "05", None, None, None),
|
||
|
},
|
||
|
datetime.date(year=1981, month=4, day=5),
|
||
|
datetime.date(year=1980, month=3, day=5),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("2050", "03", "01", None, None, None),
|
||
|
TimeTuple(
|
||
|
"13",
|
||
|
"00",
|
||
|
"00",
|
||
|
TimezoneTuple(False, True, None, None, "Z"),
|
||
|
),
|
||
|
),
|
||
|
"end": DatetimeTuple(
|
||
|
DateTuple("2050", "05", "11", None, None, None),
|
||
|
TimeTuple(
|
||
|
"15",
|
||
|
"30",
|
||
|
"00",
|
||
|
TimezoneTuple(False, True, None, None, "Z"),
|
||
|
),
|
||
|
),
|
||
|
},
|
||
|
datetime.datetime(
|
||
|
year=2050,
|
||
|
month=3,
|
||
|
day=1,
|
||
|
hour=13,
|
||
|
tzinfo=UTCOffset(name="UTC", minutes=0),
|
||
|
),
|
||
|
datetime.datetime(
|
||
|
year=2050,
|
||
|
month=5,
|
||
|
day=11,
|
||
|
hour=15,
|
||
|
minute=30,
|
||
|
tzinfo=UTCOffset(name="UTC", minutes=0),
|
||
|
),
|
||
|
),
|
||
|
# Test concise representation
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2020", "01", "01", None, None, None),
|
||
|
"end": DateTuple(None, None, "02", None, None, None),
|
||
|
},
|
||
|
datetime.date(year=2020, month=1, day=1),
|
||
|
datetime.date(year=2020, month=1, day=2),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2008", "02", "15", None, None, None),
|
||
|
"end": DateTuple(None, "03", "14", None, None, None),
|
||
|
},
|
||
|
datetime.date(year=2008, month=2, day=15),
|
||
|
datetime.date(year=2008, month=3, day=14),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("2007", "12", "14", None, None, None),
|
||
|
TimeTuple("13", "30", None, None),
|
||
|
),
|
||
|
"end": TimeTuple("15", "30", None, None),
|
||
|
},
|
||
|
datetime.datetime(year=2007, month=12, day=14, hour=13, minute=30),
|
||
|
datetime.datetime(year=2007, month=12, day=14, hour=15, minute=30),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("2007", "11", "13", None, None, None),
|
||
|
TimeTuple("09", "00", None, None),
|
||
|
),
|
||
|
"end": DatetimeTuple(
|
||
|
DateTuple(None, None, "15", None, None, None),
|
||
|
TimeTuple("17", "00", None, None),
|
||
|
),
|
||
|
},
|
||
|
datetime.datetime(year=2007, month=11, day=13, hour=9),
|
||
|
datetime.datetime(year=2007, month=11, day=15, hour=17),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("2007", "11", "13", None, None, None),
|
||
|
TimeTuple("00", "00", None, None),
|
||
|
),
|
||
|
"end": DatetimeTuple(
|
||
|
DateTuple(None, None, "16", None, None, None),
|
||
|
TimeTuple("00", "00", None, None),
|
||
|
),
|
||
|
},
|
||
|
datetime.datetime(year=2007, month=11, day=13),
|
||
|
datetime.datetime(year=2007, month=11, day=16),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("2007", "11", "13", None, None, None),
|
||
|
TimeTuple(
|
||
|
"09",
|
||
|
"00",
|
||
|
None,
|
||
|
TimezoneTuple(False, True, None, None, "Z"),
|
||
|
),
|
||
|
),
|
||
|
"end": DatetimeTuple(
|
||
|
DateTuple(None, None, "15", None, None, None),
|
||
|
TimeTuple("17", "00", None, None),
|
||
|
),
|
||
|
},
|
||
|
datetime.datetime(
|
||
|
year=2007,
|
||
|
month=11,
|
||
|
day=13,
|
||
|
hour=9,
|
||
|
tzinfo=UTCOffset(name="UTC", minutes=0),
|
||
|
),
|
||
|
datetime.datetime(
|
||
|
year=2007,
|
||
|
month=11,
|
||
|
day=15,
|
||
|
hour=17,
|
||
|
tzinfo=UTCOffset(name="UTC", minutes=0),
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("2007", "11", "13", None, None, None),
|
||
|
TimeTuple("09", "00", None, None),
|
||
|
),
|
||
|
"end": TimeTuple("12", "34.567", None, None),
|
||
|
},
|
||
|
datetime.datetime(year=2007, month=11, day=13, hour=9),
|
||
|
datetime.datetime(
|
||
|
year=2007,
|
||
|
month=11,
|
||
|
day=13,
|
||
|
hour=12,
|
||
|
minute=34,
|
||
|
second=34,
|
||
|
microsecond=20000,
|
||
|
),
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"start": DateTuple("2007", "11", "13", None, None, None),
|
||
|
"end": TimeTuple("12", "34", None, None),
|
||
|
},
|
||
|
datetime.date(year=2007, month=11, day=13),
|
||
|
datetime.datetime(year=2007, month=11, day=13, hour=12, minute=34),
|
||
|
),
|
||
|
# Make sure we truncate, not round
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
|
||
|
(
|
||
|
{
|
||
|
"start": DatetimeTuple(
|
||
|
DateTuple("1980", "03", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00.0000001", None),
|
||
|
),
|
||
|
"end": DatetimeTuple(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
TimeTuple("14", "43", "59.9999997", None),
|
||
|
),
|
||
|
},
|
||
|
datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1),
|
||
|
datetime.datetime(
|
||
|
year=1981,
|
||
|
month=4,
|
||
|
day=5,
|
||
|
hour=14,
|
||
|
minute=43,
|
||
|
second=59,
|
||
|
microsecond=999999,
|
||
|
),
|
||
|
),
|
||
|
)
|
||
|
|
||
|
for testtuple in testtuples:
|
||
|
result = PythonTimeBuilder.build_interval(**testtuple[0])
|
||
|
self.assertEqual(result[0], testtuple[1])
|
||
|
self.assertEqual(result[1], testtuple[2])
|
||
|
|
||
|
def test_build_repeating_interval(self):
|
||
|
args = {
|
||
|
"Rnn": "3",
|
||
|
"interval": IntervalTuple(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
None,
|
||
|
DurationTuple(None, None, None, "1", None, None, None),
|
||
|
),
|
||
|
}
|
||
|
results = list(PythonTimeBuilder.build_repeating_interval(**args))
|
||
|
|
||
|
self.assertEqual(results[0], datetime.date(year=1981, month=4, day=5))
|
||
|
self.assertEqual(results[1], datetime.date(year=1981, month=4, day=6))
|
||
|
self.assertEqual(results[2], datetime.date(year=1981, month=4, day=7))
|
||
|
|
||
|
args = {
|
||
|
"Rnn": "11",
|
||
|
"interval": IntervalTuple(
|
||
|
None,
|
||
|
DatetimeTuple(
|
||
|
DateTuple("1980", "03", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
DurationTuple(None, None, None, None, "1", "2", None),
|
||
|
),
|
||
|
}
|
||
|
results = list(PythonTimeBuilder.build_repeating_interval(**args))
|
||
|
|
||
|
for dateindex in compat.range(0, 11):
|
||
|
self.assertEqual(
|
||
|
results[dateindex],
|
||
|
datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1)
|
||
|
- dateindex * datetime.timedelta(hours=1, minutes=2),
|
||
|
)
|
||
|
|
||
|
args = {
|
||
|
"Rnn": "2",
|
||
|
"interval": IntervalTuple(
|
||
|
DatetimeTuple(
|
||
|
DateTuple("1980", "03", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
DatetimeTuple(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
None,
|
||
|
),
|
||
|
}
|
||
|
results = list(PythonTimeBuilder.build_repeating_interval(**args))
|
||
|
|
||
|
self.assertEqual(
|
||
|
results[0], datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1)
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
results[1], datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1)
|
||
|
)
|
||
|
|
||
|
args = {
|
||
|
"Rnn": "2",
|
||
|
"interval": IntervalTuple(
|
||
|
DatetimeTuple(
|
||
|
DateTuple("1980", "03", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
DatetimeTuple(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
None,
|
||
|
),
|
||
|
}
|
||
|
results = list(PythonTimeBuilder.build_repeating_interval(**args))
|
||
|
|
||
|
self.assertEqual(
|
||
|
results[0], datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1)
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
results[1], datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1)
|
||
|
)
|
||
|
|
||
|
args = {
|
||
|
"R": True,
|
||
|
"interval": IntervalTuple(
|
||
|
None,
|
||
|
DatetimeTuple(
|
||
|
DateTuple("1980", "03", "05", None, None, None),
|
||
|
TimeTuple("01", "01", "00", None),
|
||
|
),
|
||
|
DurationTuple(None, None, None, None, "1", "2", None),
|
||
|
),
|
||
|
}
|
||
|
resultgenerator = PythonTimeBuilder.build_repeating_interval(**args)
|
||
|
|
||
|
# Test the first 11 generated
|
||
|
for dateindex in compat.range(0, 11):
|
||
|
self.assertEqual(
|
||
|
next(resultgenerator),
|
||
|
datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1)
|
||
|
- dateindex * datetime.timedelta(hours=1, minutes=2),
|
||
|
)
|
||
|
|
||
|
args = {
|
||
|
"R": True,
|
||
|
"interval": IntervalTuple(
|
||
|
DateTuple("1981", "04", "05", None, None, None),
|
||
|
None,
|
||
|
DurationTuple(None, None, None, "1", None, None, None),
|
||
|
),
|
||
|
}
|
||
|
resultgenerator = PythonTimeBuilder.build_repeating_interval(**args)
|
||
|
|
||
|
# Test the first 11 generated
|
||
|
for dateindex in compat.range(0, 11):
|
||
|
self.assertEqual(
|
||
|
next(resultgenerator),
|
||
|
(
|
||
|
datetime.datetime(year=1981, month=4, day=5, hour=0, minute=0)
|
||
|
+ dateindex * datetime.timedelta(days=1)
|
||
|
).date(),
|
||
|
)
|
||
|
|
||
|
def test_build_timezone(self):
|
||
|
testtuples = (
|
||
|
({"Z": True, "name": "Z"}, datetime.timedelta(hours=0), "UTC"),
|
||
|
(
|
||
|
{"negative": False, "hh": "00", "mm": "00", "name": "+00:00"},
|
||
|
datetime.timedelta(hours=0),
|
||
|
"+00:00",
|
||
|
),
|
||
|
(
|
||
|
{"negative": False, "hh": "01", "mm": "00", "name": "+01:00"},
|
||
|
datetime.timedelta(hours=1),
|
||
|
"+01:00",
|
||
|
),
|
||
|
(
|
||
|
{"negative": True, "hh": "01", "mm": "00", "name": "-01:00"},
|
||
|
-datetime.timedelta(hours=1),
|
||
|
"-01:00",
|
||
|
),
|
||
|
(
|
||
|
{"negative": False, "hh": "00", "mm": "12", "name": "+00:12"},
|
||
|
datetime.timedelta(minutes=12),
|
||
|
"+00:12",
|
||
|
),
|
||
|
(
|
||
|
{"negative": False, "hh": "01", "mm": "23", "name": "+01:23"},
|
||
|
datetime.timedelta(hours=1, minutes=23),
|
||
|
"+01:23",
|
||
|
),
|
||
|
(
|
||
|
{"negative": True, "hh": "01", "mm": "23", "name": "-01:23"},
|
||
|
-datetime.timedelta(hours=1, minutes=23),
|
||
|
"-01:23",
|
||
|
),
|
||
|
(
|
||
|
{"negative": False, "hh": "00", "name": "+00"},
|
||
|
datetime.timedelta(hours=0),
|
||
|
"+00",
|
||
|
),
|
||
|
(
|
||
|
{"negative": False, "hh": "01", "name": "+01"},
|
||
|
datetime.timedelta(hours=1),
|
||
|
"+01",
|
||
|
),
|
||
|
(
|
||
|
{"negative": True, "hh": "01", "name": "-01"},
|
||
|
-datetime.timedelta(hours=1),
|
||
|
"-01",
|
||
|
),
|
||
|
(
|
||
|
{"negative": False, "hh": "12", "name": "+12"},
|
||
|
datetime.timedelta(hours=12),
|
||
|
"+12",
|
||
|
),
|
||
|
(
|
||
|
{"negative": True, "hh": "12", "name": "-12"},
|
||
|
-datetime.timedelta(hours=12),
|
||
|
"-12",
|
||
|
),
|
||
|
)
|
||
|
|
||
|
for testtuple in testtuples:
|
||
|
result = PythonTimeBuilder.build_timezone(**testtuple[0])
|
||
|
self.assertEqual(result.utcoffset(None), testtuple[1])
|
||
|
self.assertEqual(result.tzname(None), testtuple[2])
|
||
|
|
||
|
def test_range_check_date(self):
|
||
|
# 0 isn't a valid year for a Python builder
|
||
|
with self.assertRaises(YearOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_date(YYYY="0000")
|
||
|
|
||
|
# Leap year
|
||
|
# https://bitbucket.org/nielsenb/aniso8601/issues/14/parsing-ordinal-dates-should-only-allow
|
||
|
with self.assertRaises(DayOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_date(YYYY="1981", DDD="366")
|
||
|
|
||
|
def test_range_check_time(self):
|
||
|
# Hour 24 can only represent midnight
|
||
|
with self.assertRaises(MidnightBoundsError):
|
||
|
PythonTimeBuilder.build_time(hh="24", mm="00", ss="01")
|
||
|
|
||
|
with self.assertRaises(MidnightBoundsError):
|
||
|
PythonTimeBuilder.build_time(hh="24", mm="00.1")
|
||
|
|
||
|
with self.assertRaises(MidnightBoundsError):
|
||
|
PythonTimeBuilder.build_time(hh="24", mm="01")
|
||
|
|
||
|
with self.assertRaises(MidnightBoundsError):
|
||
|
PythonTimeBuilder.build_time(hh="24.1")
|
||
|
|
||
|
def test_range_check_duration(self):
|
||
|
with self.assertRaises(YearOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_duration(
|
||
|
PnY=str((datetime.timedelta.max.days // 365) + 1)
|
||
|
)
|
||
|
|
||
|
with self.assertRaises(MonthOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_duration(
|
||
|
PnM=str((datetime.timedelta.max.days // 30) + 1)
|
||
|
)
|
||
|
|
||
|
with self.assertRaises(DayOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_duration(PnD=str(datetime.timedelta.max.days + 1))
|
||
|
|
||
|
with self.assertRaises(WeekOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_duration(
|
||
|
PnW=str((datetime.timedelta.max.days // 7) + 1)
|
||
|
)
|
||
|
|
||
|
with self.assertRaises(HoursOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_duration(
|
||
|
TnH=str((datetime.timedelta.max.days * 24) + 24)
|
||
|
)
|
||
|
|
||
|
with self.assertRaises(MinutesOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_duration(
|
||
|
TnM=str((datetime.timedelta.max.days * 24 * 60) + 24 * 60)
|
||
|
)
|
||
|
|
||
|
with self.assertRaises(SecondsOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_duration(
|
||
|
TnS=str((datetime.timedelta.max.days * 24 * 60 * 60) + 24 * 60 * 60)
|
||
|
)
|
||
|
|
||
|
# Split max range across all parts
|
||
|
maxpart = datetime.timedelta.max.days // 7
|
||
|
|
||
|
with self.assertRaises(DayOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_duration(
|
||
|
PnY=str((maxpart // 365) + 1),
|
||
|
PnM=str((maxpart // 30) + 1),
|
||
|
PnD=str((maxpart + 1)),
|
||
|
PnW=str((maxpart // 7) + 1),
|
||
|
TnH=str((maxpart * 24) + 1),
|
||
|
TnM=str((maxpart * 24 * 60) + 1),
|
||
|
TnS=str((maxpart * 24 * 60 * 60) + 1),
|
||
|
)
|
||
|
|
||
|
def test_range_check_interval(self):
|
||
|
with self.assertRaises(YearOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_interval(
|
||
|
start=DateTuple("0007", None, None, None, None, None),
|
||
|
duration=DurationTuple(
|
||
|
None, None, None, str(datetime.timedelta.max.days), None, None, None
|
||
|
),
|
||
|
)
|
||
|
|
||
|
with self.assertRaises(YearOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_interval(
|
||
|
start=DatetimeTuple(
|
||
|
DateTuple("0007", None, None, None, None, None),
|
||
|
TimeTuple("1", None, None, None),
|
||
|
),
|
||
|
duration=DurationTuple(
|
||
|
str(datetime.timedelta.max.days // 365),
|
||
|
None,
|
||
|
None,
|
||
|
None,
|
||
|
None,
|
||
|
None,
|
||
|
None,
|
||
|
),
|
||
|
)
|
||
|
|
||
|
with self.assertRaises(YearOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_interval(
|
||
|
end=DateTuple("0001", None, None, None, None, None),
|
||
|
duration=DurationTuple("3", None, None, None, None, None, None),
|
||
|
)
|
||
|
|
||
|
with self.assertRaises(YearOutOfBoundsError):
|
||
|
PythonTimeBuilder.build_interval(
|
||
|
end=DatetimeTuple(
|
||
|
DateTuple("0001", None, None, None, None, None),
|
||
|
TimeTuple("1", None, None, None),
|
||
|
),
|
||
|
duration=DurationTuple("2", None, None, None, None, None, None),
|
||
|
)
|
||
|
|
||
|
def test_build_week_date(self):
|
||
|
weekdate = PythonTimeBuilder._build_week_date(2009, 1)
|
||
|
self.assertEqual(weekdate, datetime.date(year=2008, month=12, day=29))
|
||
|
|
||
|
weekdate = PythonTimeBuilder._build_week_date(2009, 53, isoday=7)
|
||
|
self.assertEqual(weekdate, datetime.date(year=2010, month=1, day=3))
|
||
|
|
||
|
def test_build_ordinal_date(self):
|
||
|
ordinaldate = PythonTimeBuilder._build_ordinal_date(1981, 95)
|
||
|
self.assertEqual(ordinaldate, datetime.date(year=1981, month=4, day=5))
|
||
|
|
||
|
def test_iso_year_start(self):
|
||
|
yearstart = PythonTimeBuilder._iso_year_start(2004)
|
||
|
self.assertEqual(yearstart, datetime.date(year=2003, month=12, day=29))
|
||
|
|
||
|
yearstart = PythonTimeBuilder._iso_year_start(2010)
|
||
|
self.assertEqual(yearstart, datetime.date(year=2010, month=1, day=4))
|
||
|
|
||
|
yearstart = PythonTimeBuilder._iso_year_start(2009)
|
||
|
self.assertEqual(yearstart, datetime.date(year=2008, month=12, day=29))
|
||
|
|
||
|
def test_date_generator(self):
|
||
|
startdate = datetime.date(year=2018, month=8, day=29)
|
||
|
timedelta = datetime.timedelta(days=1)
|
||
|
iterations = 10
|
||
|
|
||
|
generator = PythonTimeBuilder._date_generator(startdate, timedelta, iterations)
|
||
|
|
||
|
results = list(generator)
|
||
|
|
||
|
for dateindex in compat.range(0, 10):
|
||
|
self.assertEqual(
|
||
|
results[dateindex],
|
||
|
datetime.date(year=2018, month=8, day=29)
|
||
|
+ dateindex * datetime.timedelta(days=1),
|
||
|
)
|
||
|
|
||
|
def test_date_generator_unbounded(self):
|
||
|
startdate = datetime.date(year=2018, month=8, day=29)
|
||
|
timedelta = datetime.timedelta(days=5)
|
||
|
|
||
|
generator = PythonTimeBuilder._date_generator_unbounded(startdate, timedelta)
|
||
|
|
||
|
# Check the first 10 results
|
||
|
for dateindex in compat.range(0, 10):
|
||
|
self.assertEqual(
|
||
|
next(generator),
|
||
|
datetime.date(year=2018, month=8, day=29)
|
||
|
+ dateindex * datetime.timedelta(days=5),
|
||
|
)
|
||
|
|
||
|
def test_distribute_microseconds(self):
|
||
|
self.assertEqual(PythonTimeBuilder._distribute_microseconds(1, (), ()), (1,))
|
||
|
self.assertEqual(
|
||
|
PythonTimeBuilder._distribute_microseconds(11, (0,), (10,)), (1, 1)
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
PythonTimeBuilder._distribute_microseconds(211, (0, 0), (100, 10)),
|
||
|
(2, 1, 1),
|
||
|
)
|
||
|
|
||
|
self.assertEqual(PythonTimeBuilder._distribute_microseconds(1, (), ()), (1,))
|
||
|
self.assertEqual(
|
||
|
PythonTimeBuilder._distribute_microseconds(11, (5,), (10,)), (6, 1)
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
PythonTimeBuilder._distribute_microseconds(211, (10, 5), (100, 10)),
|
||
|
(12, 6, 1),
|
||
|
)
|