232 lines
7.0 KiB
Python
232 lines
7.0 KiB
Python
|
from datetime import datetime
|
||
|
from zoneinfo import ZoneInfo
|
||
|
|
||
|
from timedeltacal import timedeltacal
|
||
|
|
||
|
# Some basic tests. These serve as a specification. All the tests use timezone
|
||
|
# aware datetimes in a timezone with DST, since this is the most complex case.
|
||
|
# Naive datetimes and dates should work analogously.
|
||
|
|
||
|
def test_add_same_day():
|
||
|
t0 = datetime(2022, 4, 17, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(hours=2, minutes=34, seconds=56, milliseconds=789)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == t0.month
|
||
|
assert t1.day == t0.day
|
||
|
assert t1.hour == 13
|
||
|
assert t1.minute == 12
|
||
|
assert t1.second == 17
|
||
|
assert t1.microsecond == 789000
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
|
||
|
def test_add_next_day():
|
||
|
t0 = datetime(2022, 4, 17, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(hours=13, minutes=34, seconds=56, milliseconds=789)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == t0.month
|
||
|
assert t1.day == 18
|
||
|
assert t1.hour == 0
|
||
|
assert t1.minute == 12
|
||
|
assert t1.second == 17
|
||
|
assert t1.microsecond == 789000
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
def test_add_days():
|
||
|
t0 = datetime(2022, 4, 17, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(days=1)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == t0.month
|
||
|
assert t1.day == 18
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
# Add days -> next month
|
||
|
def test_add_days_to_next_month():
|
||
|
t0 = datetime(2022, 4, 17, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(days=20)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == 5
|
||
|
assert t1.day == 7
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
# Add months
|
||
|
def test_add_months():
|
||
|
t0 = datetime(2022, 4, 17, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(months=1)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == 5
|
||
|
assert t1.day == 17
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
# Add years
|
||
|
def test_add_years():
|
||
|
t0 = datetime(2022, 4, 17, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(years=1)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == 2023
|
||
|
assert t1.month == 4
|
||
|
assert t1.day == 17
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
|
||
|
# Same tests, but crossing a DST boundary
|
||
|
def test_add_same_day_dst():
|
||
|
t0 = datetime(2022, 3, 27, 1, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(hours=2, minutes=34, seconds=56, milliseconds=789)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == t0.month
|
||
|
assert t1.day == t0.day
|
||
|
assert t1.hour == 5
|
||
|
assert t1.minute == 12
|
||
|
assert t1.second == 17
|
||
|
assert t1.microsecond == 789000
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
def test_add_next_day_dst():
|
||
|
t0 = datetime(2022, 3, 26, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(hours=23, minutes=34, seconds=56, milliseconds=789)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == t0.month
|
||
|
assert t1.day == 27
|
||
|
assert t1.hour == 11
|
||
|
assert t1.minute == 12
|
||
|
assert t1.second == 17
|
||
|
assert t1.microsecond == 789000
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
def test_add_days_dst():
|
||
|
t0 = datetime(2022, 3, 26, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(days=1)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == t0.month
|
||
|
assert t1.day == 27
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
# Add days -> next month
|
||
|
def test_add_days_to_next_month_dst():
|
||
|
t0 = datetime(2022, 3, 26, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(days=20)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == 4
|
||
|
assert t1.day == 15
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
# Add months
|
||
|
def test_add_months_dst():
|
||
|
t0 = datetime(2022, 3, 26, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(months=1)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == 4
|
||
|
assert t1.day == t0.day
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
# Add years
|
||
|
def test_add_years_dst():
|
||
|
t0 = datetime(2022, 3, 26, 10, 37, 21, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(years=1)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == 2023
|
||
|
assert t1.month == 3
|
||
|
assert t1.day == 26
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
# Month arithmetic is saturating: If the arithmetic result would result in a
|
||
|
# day of the month which doesn't exist, we choose the last day of the month
|
||
|
# instead.
|
||
|
|
||
|
def test_add_months_feb():
|
||
|
t0 = datetime(2022, 1, 31, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(months=1)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == 2
|
||
|
assert t1.day == 28
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
def test_add_months_mar():
|
||
|
t0 = datetime(2022, 1, 31, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(months=2)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == 3
|
||
|
assert t1.day == 31
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
def test_add_months_apr():
|
||
|
t0 = datetime(2022, 1, 31, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(months=3)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == t0.year
|
||
|
assert t1.month == 4
|
||
|
assert t1.day == 30
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
def test_add_months_feb_leap():
|
||
|
t0 = datetime(2022, 1, 31, tzinfo=ZoneInfo("Europe/Vienna"))
|
||
|
d = timedeltacal(months=25)
|
||
|
t1 = t0 + d
|
||
|
assert t1.year == 2024
|
||
|
assert t1.month == 2
|
||
|
assert t1.day == 29
|
||
|
assert t1.hour == t0.hour
|
||
|
assert t1.minute == t0.minute
|
||
|
assert t1.second == t0.second
|
||
|
assert t1.microsecond == t0.microsecond
|
||
|
assert t1.tzinfo is t0.tzinfo
|
||
|
|
||
|
|