diff options
Diffstat (limited to 'tests/datetime')
-rw-r--r-- | tests/datetime/__init__.py | 0 | ||||
-rw-r--r-- | tests/datetime/test_add.py | 268 | ||||
-rw-r--r-- | tests/datetime/test_behavior.py | 172 | ||||
-rw-r--r-- | tests/datetime/test_comparison.py | 394 | ||||
-rw-r--r-- | tests/datetime/test_construct.py | 182 | ||||
-rw-r--r-- | tests/datetime/test_create_from_timestamp.py | 24 | ||||
-rw-r--r-- | tests/datetime/test_day_of_week_modifiers.py | 314 | ||||
-rw-r--r-- | tests/datetime/test_diff.py | 880 | ||||
-rw-r--r-- | tests/datetime/test_fluent_setters.py | 181 | ||||
-rw-r--r-- | tests/datetime/test_from_format.py | 203 | ||||
-rw-r--r-- | tests/datetime/test_getters.py | 248 | ||||
-rw-r--r-- | tests/datetime/test_naive.py | 78 | ||||
-rw-r--r-- | tests/datetime/test_replace.py | 61 | ||||
-rw-r--r-- | tests/datetime/test_start_end_of.py | 285 | ||||
-rw-r--r-- | tests/datetime/test_strings.py | 141 | ||||
-rw-r--r-- | tests/datetime/test_sub.py | 251 | ||||
-rw-r--r-- | tests/datetime/test_timezone.py | 38 |
17 files changed, 3720 insertions, 0 deletions
diff --git a/tests/datetime/__init__.py b/tests/datetime/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/datetime/__init__.py diff --git a/tests/datetime/test_add.py b/tests/datetime/test_add.py new file mode 100644 index 0000000..87ea39f --- /dev/null +++ b/tests/datetime/test_add.py @@ -0,0 +1,268 @@ +from __future__ import annotations + +from datetime import timedelta + +import pytest + +import pendulum + +from tests.conftest import assert_datetime + + +def test_add_years_positive(): + assert pendulum.datetime(1975, 1, 1).add(years=1).year == 1976 + + +def test_add_years_zero(): + assert pendulum.datetime(1975, 1, 1).add(years=0).year == 1975 + + +def test_add_years_negative(): + assert pendulum.datetime(1975, 1, 1).add(years=-1).year == 1974 + + +def test_add_months_positive(): + assert pendulum.datetime(1975, 12, 1).add(months=1).month == 1 + + +def test_add_months_zero(): + assert pendulum.datetime(1975, 12, 1).add(months=0).month == 12 + + +def test_add_months_negative(): + assert pendulum.datetime(1975, 12, 1).add(months=-1).month == 11 + + +def test_add_month_with_overflow(): + assert pendulum.datetime(2012, 1, 31).add(months=1).month == 2 + + +def test_add_days_positive(): + assert pendulum.datetime(1975, 5, 31).add(days=1).day == 1 + + +def test_add_days_zero(): + assert pendulum.datetime(1975, 5, 31).add(days=0).day == 31 + + +def test_add_days_negative(): + assert pendulum.datetime(1975, 5, 31).add(days=-1).day == 30 + + +def test_add_weeks_positive(): + assert pendulum.datetime(1975, 5, 21).add(weeks=1).day == 28 + + +def test_add_weeks_zero(): + assert pendulum.datetime(1975, 5, 21).add(weeks=0).day == 21 + + +def test_add_weeks_negative(): + assert pendulum.datetime(1975, 5, 21).add(weeks=-1).day == 14 + + +def test_add_hours_positive(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).add(hours=1).hour == 1 + + +def test_add_hours_zero(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).add(hours=0).hour == 0 + + +def test_add_hours_negative(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).add(hours=-1).hour == 23 + + +def test_add_minutes_positive(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).add(minutes=1).minute == 1 + + +def test_add_minutes_zero(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).add(minutes=0).minute == 0 + + +def test_add_minutes_negative(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).add(minutes=-1).minute == 59 + + +def test_add_seconds_positive(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).add(seconds=1).second == 1 + + +def test_add_seconds_zero(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).add(seconds=0).second == 0 + + +def test_add_seconds_negative(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).add(seconds=-1).second == 59 + + +def test_add_timedelta(): + delta = timedelta(days=6, seconds=45, microseconds=123456) + d = pendulum.datetime(2015, 3, 14, 3, 12, 15, 654321) + + d = d + delta + assert d.day == 20 + assert d.minute == 13 + assert d.second == 0 + assert d.microsecond == 777777 + + +def test_add_duration(): + duration = pendulum.duration( + years=2, months=3, days=6, seconds=45, microseconds=123456 + ) + d = pendulum.datetime(2015, 3, 14, 3, 12, 15, 654321) + + d = d + duration + assert d.year == 2017 + assert d.month == 6 + assert d.day == 20 + assert d.hour == 3 + assert d.minute == 13 + assert d.second == 0 + assert d.microsecond == 777777 + + +def test_addition_invalid_type(): + d = pendulum.datetime(2015, 3, 14, 3, 12, 15, 654321) + + with pytest.raises(TypeError): + d + 3 + + with pytest.raises(TypeError): + 3 + d + + +def test_add_to_fixed_timezones(): + dt = pendulum.parse("2015-03-08T01:00:00-06:00") + dt = dt.add(weeks=1) + dt = dt.add(hours=1) + + assert_datetime(dt, 2015, 3, 15, 2, 0, 0) + assert dt.timezone_name == "-06:00" + assert dt.offset == -6 * 3600 + + +def test_add_time_to_new_transition_skipped(): + dt = pendulum.datetime(2013, 3, 31, 1, 59, 59, 999999, tz="Europe/Paris") + + assert_datetime(dt, 2013, 3, 31, 1, 59, 59, 999999) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 3600 + assert not dt.is_dst() + + dt = dt.add(microseconds=1) + + assert_datetime(dt, 2013, 3, 31, 3, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 7200 + assert dt.is_dst() + + dt = pendulum.datetime(2013, 3, 10, 1, 59, 59, 999999, tz="America/New_York") + + assert_datetime(dt, 2013, 3, 10, 1, 59, 59, 999999) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -5 * 3600 + assert not dt.is_dst() + + dt = dt.add(microseconds=1) + + assert_datetime(dt, 2013, 3, 10, 3, 0, 0, 0) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -4 * 3600 + assert dt.is_dst() + + dt = pendulum.datetime(1957, 4, 28, 1, 59, 59, 999999, tz="America/New_York") + + assert_datetime(dt, 1957, 4, 28, 1, 59, 59, 999999) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -5 * 3600 + assert not dt.is_dst() + + dt = dt.add(microseconds=1) + + assert_datetime(dt, 1957, 4, 28, 3, 0, 0, 0) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -4 * 3600 + assert dt.is_dst() + + +def test_add_time_to_new_transition_skipped_big(): + dt = pendulum.datetime(2013, 3, 31, 1, tz="Europe/Paris") + + assert_datetime(dt, 2013, 3, 31, 1, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 3600 + assert not dt.is_dst() + + dt = dt.add(weeks=1) + + assert_datetime(dt, 2013, 4, 7, 1, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 7200 + assert dt.is_dst() + + +def test_add_time_to_new_transition_repeated(): + dt = pendulum.datetime(2013, 10, 27, 1, 59, 59, 999999, tz="Europe/Paris") + dt = dt.add(hours=1) + + assert_datetime(dt, 2013, 10, 27, 2, 59, 59, 999999) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 7200 + assert dt.is_dst() + + dt = dt.add(microseconds=1) + + assert_datetime(dt, 2013, 10, 27, 2, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 3600 + assert not dt.is_dst() + + dt = pendulum.datetime(2013, 11, 3, 0, 59, 59, 999999, tz="America/New_York") + dt = dt.add(hours=1) + + assert_datetime(dt, 2013, 11, 3, 1, 59, 59, 999999) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -4 * 3600 + assert dt.is_dst() + + dt = dt.add(microseconds=1) + + assert_datetime(dt, 2013, 11, 3, 1, 0, 0, 0) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -5 * 3600 + assert not dt.is_dst() + + +def test_add_time_to_new_transition_repeated_big(): + dt = pendulum.datetime(2013, 10, 27, 1, tz="Europe/Paris") + + assert_datetime(dt, 2013, 10, 27, 1, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 7200 + assert dt.is_dst() + + dt = dt.add(weeks=1) + + assert_datetime(dt, 2013, 11, 3, 1, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 3600 + assert not dt.is_dst() + + +def test_add_interval(): + dt = pendulum.datetime(2017, 3, 11, 10, 45, tz="America/Los_Angeles") + new = dt + pendulum.duration(hours=24) + + assert_datetime(new, 2017, 3, 12, 11, 45) + + +def test_period_over_midnight_tz(): + start = pendulum.datetime(2018, 2, 25, tz="Europe/Paris") + end = start.add(hours=1) + period = end - start + new_end = start + period + + assert new_end == end diff --git a/tests/datetime/test_behavior.py b/tests/datetime/test_behavior.py new file mode 100644 index 0000000..e02323a --- /dev/null +++ b/tests/datetime/test_behavior.py @@ -0,0 +1,172 @@ +from __future__ import annotations + +import pickle + +from copy import deepcopy +from datetime import date +from datetime import datetime +from datetime import time + +import pytest + +import pendulum + +from pendulum import timezone +from pendulum.tz.timezone import Timezone +from pendulum.utils._compat import zoneinfo + + +@pytest.fixture +def p(): + return pendulum.datetime(2016, 8, 27, 12, 34, 56, 123456, tz="Europe/Paris") + + +@pytest.fixture +def p1(p): + return p.in_tz("America/New_York") + + +@pytest.fixture +def dt(): + tz = timezone("Europe/Paris") + + return tz.convert(datetime(2016, 8, 27, 12, 34, 56, 123456)) + + +def test_timetuple(p, dt): + assert dt.timetuple() == p.timetuple() + + +def test_utctimetuple(p, dt): + assert dt.utctimetuple() == p.utctimetuple() + + +def test_date(p, dt): + assert p.date() == dt.date() + + +def test_time(p, dt): + assert p.time() == dt.time() + + +def test_timetz(p, dt): + assert p.timetz() == dt.timetz() + + +def test_astimezone(p, dt, p1): + assert p.astimezone(p1.tzinfo) == dt.astimezone(p1.tzinfo) + + +def test_ctime(p, dt): + assert p.ctime() == dt.ctime() + + +def test_isoformat(p, dt): + assert p.isoformat() == dt.isoformat() + + +def test_utcoffset(p, dt): + assert p.utcoffset() == dt.utcoffset() + + +def test_tzname(p, dt): + assert p.tzname() == dt.tzname() + + +def test_dst(p, dt): + assert p.dst() == dt.dst() + + +def test_toordinal(p, dt): + assert p.toordinal() == dt.toordinal() + + +def test_weekday(p, dt): + assert p.weekday() == dt.weekday() + + +def test_isoweekday(p, dt): + assert p.isoweekday() == dt.isoweekday() + + +def test_isocalendar(p, dt): + assert p.isocalendar() == dt.isocalendar() + + +def test_fromtimestamp(): + p = pendulum.DateTime.fromtimestamp(0, pendulum.UTC) + dt = datetime.fromtimestamp(0, pendulum.UTC) + + assert p == dt + + +def test_utcfromtimestamp(): + p = pendulum.DateTime.utcfromtimestamp(0) + dt = datetime.utcfromtimestamp(0) + + assert p == dt + + +def test_fromordinal(): + assert datetime.fromordinal(730120) == pendulum.DateTime.fromordinal(730120) + + +def test_combine(): + p = pendulum.DateTime.combine(date(2016, 1, 1), time(1, 2, 3, 123456)) + dt = datetime.combine(date(2016, 1, 1), time(1, 2, 3, 123456)) + + assert p == dt + + +def test_hash(p, dt): + assert hash(p) == hash(dt) + + dt1 = pendulum.datetime(2016, 8, 27, 12, 34, 56, 123456, tz="Europe/Paris") + dt2 = pendulum.datetime(2016, 8, 27, 12, 34, 56, 123456, tz="Europe/Paris") + dt3 = pendulum.datetime(2016, 8, 27, 12, 34, 56, 123456, tz="America/Toronto") + + assert hash(dt1) == hash(dt2) + assert hash(dt1) != hash(dt3) + + +def test_pickle(): + dt1 = pendulum.datetime(2016, 8, 27, 12, 34, 56, 123456, tz="Europe/Paris") + s = pickle.dumps(dt1) + dt2 = pickle.loads(s) + + assert dt1 == dt2 + + +def test_pickle_with_integer_tzinfo(): + dt1 = pendulum.datetime(2016, 8, 27, 12, 34, 56, 123456, tz=0) + s = pickle.dumps(dt1) + dt2 = pickle.loads(s) + + assert dt1 == dt2 + + +def test_proper_dst(): + dt = pendulum.datetime(1941, 7, 1, tz="Europe/Amsterdam") + native_dt = datetime(1941, 7, 1, tzinfo=zoneinfo.ZoneInfo("Europe/Amsterdam")) + + assert dt.dst() == native_dt.dst() + + +def test_deepcopy(): + dt = pendulum.datetime(1941, 7, 1, tz="Europe/Amsterdam") + + assert dt == deepcopy(dt) + + +def test_pickle_timezone(): + dt1 = pendulum.timezone("Europe/Amsterdam") + s = pickle.dumps(dt1) + dt2 = pickle.loads(s) + + assert isinstance(dt2, Timezone) + + dt1 = pendulum.timezone("UTC") + s = pickle.dumps(dt1) + dt2 = pickle.loads(s) + + assert isinstance(dt2, Timezone) diff --git a/tests/datetime/test_comparison.py b/tests/datetime/test_comparison.py new file mode 100644 index 0000000..ad81e73 --- /dev/null +++ b/tests/datetime/test_comparison.py @@ -0,0 +1,394 @@ +from __future__ import annotations + +from datetime import datetime + +import pytz + +import pendulum + +from tests.conftest import assert_datetime + + +def test_equal_to_true(): + d1 = pendulum.datetime(2000, 1, 1, 1, 2, 3) + d2 = pendulum.datetime(2000, 1, 1, 1, 2, 3) + d3 = datetime(2000, 1, 1, 1, 2, 3, tzinfo=pendulum.UTC) + + assert d2 == d1 + assert d3 == d1 + + +def test_equal_to_false(): + d1 = pendulum.datetime(2000, 1, 1, 1, 2, 3) + d2 = pendulum.datetime(2000, 1, 2, 1, 2, 3) + d3 = datetime(2000, 1, 2, 1, 2, 3, tzinfo=pendulum.UTC) + + assert d2 != d1 + assert d3 != d1 + + +def test_equal_with_timezone_true(): + d1 = pendulum.datetime(2000, 1, 1, 12, 0, 0, tz="America/Toronto") + d2 = pendulum.datetime(2000, 1, 1, 9, 0, 0, tz="America/Vancouver") + d3 = datetime(2000, 1, 1, 12, 0, 0, tzinfo=pendulum.timezone("America/Toronto")) + + assert d2 == d1 + assert d3 == d1 + + +def test_equal_with_timezone_false(): + d1 = pendulum.datetime(2000, 1, 1, tz="America/Toronto") + d2 = pendulum.datetime(2000, 1, 1, tz="America/Vancouver") + d3 = datetime(2000, 1, 1, tzinfo=pendulum.timezone("America/Toronto")) + + assert d2 != d1 + assert d3 == d1 + + +def test_not_equal_to_true(): + d1 = pendulum.datetime(2000, 1, 1, 1, 2, 3) + d2 = pendulum.datetime(2000, 1, 2, 1, 2, 3) + d3 = datetime(2000, 1, 2, 1, 2, 3, tzinfo=pendulum.UTC) + + assert d2 != d1 + assert d3 != d1 + + +def test_not_equal_to_false(): + d1 = pendulum.datetime(2000, 1, 1, 1, 2, 3) + d2 = pendulum.datetime(2000, 1, 1, 1, 2, 3) + d3 = datetime(2000, 1, 1, 1, 2, 3, tzinfo=pendulum.UTC) + + assert d2 == d1 + assert d3 == d1 + + +def test_not_equal_with_timezone_true(): + d1 = pendulum.datetime(2000, 1, 1, tz="America/Toronto") + d2 = pendulum.datetime(2000, 1, 1, tz="America/Vancouver") + d3 = datetime(2000, 1, 1, tzinfo=pendulum.timezone("America/Toronto")) + + assert d2 != d1 + assert d3 == d1 + + +def test_not_equal_to_none(): + d1 = pendulum.datetime(2000, 1, 1, 1, 2, 3) + + assert d1 != None # noqa + + +def test_greater_than_true(): + d1 = pendulum.datetime(2000, 1, 1) + d2 = pendulum.datetime(1999, 12, 31) + d3 = datetime(1999, 12, 31, tzinfo=pendulum.UTC) + + assert d1 > d2 + assert d1 > d3 + + +def test_greater_than_false(): + d1 = pendulum.datetime(2000, 1, 1) + d2 = pendulum.datetime(2000, 1, 2) + d3 = datetime(2000, 1, 2, tzinfo=pendulum.UTC) + + assert not d1 > d2 + assert not d1 > d3 + + +def test_greater_than_with_timezone_true(): + d1 = pendulum.datetime(2000, 1, 1, 12, 0, 0, tz="America/Toronto") + d2 = pendulum.datetime(2000, 1, 1, 8, 59, 59, tz="America/Vancouver") + d3 = pytz.timezone("America/Vancouver").localize(datetime(2000, 1, 1, 8, 59, 59)) + + assert d1 > d2 + assert d1 > d3 + + +def test_greater_than_with_timezone_false(): + d1 = pendulum.datetime(2000, 1, 1, 12, 0, 0, tz="America/Toronto") + d2 = pendulum.datetime(2000, 1, 1, 9, 0, 1, tz="America/Vancouver") + d3 = pytz.timezone("America/Vancouver").localize(datetime(2000, 1, 1, 9, 0, 1)) + + assert not d1 > d2 + assert not d1 > d3 + + +def test_greater_than_or_equal_true(): + d1 = pendulum.datetime(2000, 1, 1) + d2 = pendulum.datetime(1999, 12, 31) + d3 = datetime(1999, 12, 31, tzinfo=pendulum.UTC) + + assert d1 >= d2 + assert d1 >= d3 + + +def test_greater_than_or_equal_true_equal(): + d1 = pendulum.datetime(2000, 1, 1) + d2 = pendulum.datetime(2000, 1, 1) + d3 = datetime(2000, 1, 1, tzinfo=pendulum.UTC) + + assert d1 >= d2 + assert d1 >= d3 + + +def test_greater_than_or_equal_false(): + d1 = pendulum.datetime(2000, 1, 1) + d2 = pendulum.datetime(2000, 1, 2) + d3 = datetime(2000, 1, 2, tzinfo=pendulum.UTC) + + assert not d1 >= d2 + assert not d1 >= d3 + + +def test_greater_than_or_equal_with_timezone_true(): + d1 = pendulum.datetime(2000, 1, 1, 12, 0, 0, tz="America/Toronto") + d2 = pendulum.datetime(2000, 1, 1, 8, 59, 59, tz="America/Vancouver") + d3 = pytz.timezone("America/Vancouver").localize(datetime(2000, 1, 1, 8, 59, 59)) + + assert d1 >= d2 + assert d1 >= d3 + + +def test_greater_than_or_equal_with_timezone_false(): + d1 = pendulum.datetime(2000, 1, 1, 12, 0, 0, tz="America/Toronto") + d2 = pendulum.datetime(2000, 1, 1, 9, 0, 1, tz="America/Vancouver") + d3 = pytz.timezone("America/Vancouver").localize(datetime(2000, 1, 1, 9, 0, 1)) + + assert not d1 >= d2 + assert not d1 >= d3 + + +def test_less_than_true(): + d1 = pendulum.datetime(2000, 1, 1) + d2 = pendulum.datetime(2000, 1, 2) + d3 = datetime(2000, 1, 2, tzinfo=pendulum.UTC) + + assert d1 < d2 + assert d1 < d3 + + +def test_less_than_false(): + d1 = pendulum.datetime(2000, 1, 2) + d2 = pendulum.datetime(2000, 1, 1) + d3 = datetime(2000, 1, 1, tzinfo=pendulum.UTC) + + assert not d1 < d2 + assert not d1 < d3 + + +def test_less_than_with_timezone_true(): + d1 = pendulum.datetime(2000, 1, 1, 8, 59, 59, tz="America/Vancouver") + d2 = pendulum.datetime(2000, 1, 1, 12, 0, 0, tz="America/Toronto") + d3 = pytz.timezone("America/Toronto").localize(datetime(2000, 1, 1, 12, 0, 0)) + + assert d1 < d2 + assert d1 < d3 + + +def test_less_than_with_timezone_false(): + d1 = pendulum.datetime(2000, 1, 1, 9, 0, 1, tz="America/Vancouver") + d2 = pendulum.datetime(2000, 1, 1, 12, 0, 0, tz="America/Toronto") + d3 = pytz.timezone("America/Toronto").localize(datetime(2000, 1, 1, 12, 0, 0)) + + assert not d1 < d2 + assert not d1 < d3 + + +def test_less_than_or_equal_true(): + d1 = pendulum.datetime(2000, 1, 1) + d2 = pendulum.datetime(2000, 1, 2) + d3 = datetime(2000, 1, 2, tzinfo=pendulum.UTC) + + assert d1 <= d2 + assert d1 <= d3 + + +def test_less_than_or_equal_true_equal(): + d1 = pendulum.datetime(2000, 1, 1) + d2 = pendulum.datetime(2000, 1, 1) + d3 = datetime(2000, 1, 1, tzinfo=pendulum.UTC) + + assert d1 <= d2 + assert d1 <= d3 + + +def test_less_than_or_equal_false(): + d1 = pendulum.datetime(2000, 1, 2) + d2 = pendulum.datetime(2000, 1, 1) + d3 = datetime(2000, 1, 1, tzinfo=pendulum.UTC) + + assert not d1 <= d2 + assert not d1 <= d3 + + +def test_less_than_or_equal_with_timezone_true(): + d1 = pendulum.datetime(2000, 1, 1, 8, 59, 59, tz="America/Vancouver") + d2 = pendulum.datetime(2000, 1, 1, 12, 0, 0, tz="America/Toronto") + d3 = pytz.timezone("America/Toronto").localize(datetime(2000, 1, 1, 12, 0, 0)) + + assert d1 <= d2 + assert d1 <= d3 + + +def test_less_than_or_equal_with_timezone_false(): + d1 = pendulum.datetime(2000, 1, 1, 9, 0, 1, tz="America/Vancouver") + d2 = pendulum.datetime(2000, 1, 1, 12, 0, 0, tz="America/Toronto") + d3 = pytz.timezone("America/Toronto").localize(datetime(2000, 1, 1, 12, 0, 0)) + + assert not d1 <= d2 + assert not d1 <= d3 + + +def test_is_anniversary(): + with pendulum.travel_to(pendulum.now()): + d = pendulum.now() + an_anniversary = d.subtract(years=1) + assert an_anniversary.is_anniversary() + not_an_anniversary = d.subtract(days=1) + assert not not_an_anniversary.is_anniversary() + also_not_an_anniversary = d.add(days=2) + assert not also_not_an_anniversary.is_anniversary() + + d1 = pendulum.datetime(1987, 4, 23) + d2 = pendulum.datetime(2014, 9, 26) + d3 = pendulum.datetime(2014, 4, 23) + assert not d2.is_anniversary(d1) + assert d3.is_anniversary(d1) + + +def test_is_birthday(): # backward compatibility + with pendulum.travel_to(pendulum.now()): + d = pendulum.now() + an_anniversary = d.subtract(years=1) + assert an_anniversary.is_birthday() + not_an_anniversary = d.subtract(days=1) + assert not not_an_anniversary.is_birthday() + also_not_an_anniversary = d.add(days=2) + assert not also_not_an_anniversary.is_birthday() + + d1 = pendulum.datetime(1987, 4, 23) + d2 = pendulum.datetime(2014, 9, 26) + d3 = pendulum.datetime(2014, 4, 23) + assert not d2.is_birthday(d1) + assert d3.is_birthday(d1) + + +def test_closest(): + instance = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt1 = pendulum.datetime(2015, 5, 28, 11, 0, 0) + dt2 = pendulum.datetime(2015, 5, 28, 14, 0, 0) + closest = instance.closest(dt1, dt2) + assert closest == dt1 + + closest = instance.closest(dt2, dt1) + assert closest == dt1 + + dts = [ + pendulum.datetime(2015, 5, 28, 16, 0, 0) + pendulum.duration(hours=x) + for x in range(4) + ] + closest = instance.closest(*dts) + assert closest == dts[0] + + closest = instance.closest(*(dts[::-1])) + assert closest == dts[0] + + +def test_closest_with_datetime(): + instance = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt1 = datetime(2015, 5, 28, 11, 0, 0) + dt2 = datetime(2015, 5, 28, 14, 0, 0) + closest = instance.closest(dt1, dt2) + assert_datetime(closest, 2015, 5, 28, 11, 0, 0) + + dts = [ + pendulum.datetime(2015, 5, 28, 16, 0, 0) + pendulum.duration(hours=x) + for x in range(4) + ] + closest = instance.closest(dt1, dt2, *dts) + + assert_datetime(closest, 2015, 5, 28, 11, 0, 0) + + +def test_closest_with_equals(): + instance = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt1 = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt2 = pendulum.datetime(2015, 5, 28, 14, 0, 0) + closest = instance.closest(dt1, dt2) + assert closest == dt1 + + +def test_farthest(): + instance = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt1 = pendulum.datetime(2015, 5, 28, 11, 0, 0) + dt2 = pendulum.datetime(2015, 5, 28, 14, 0, 0) + farthest = instance.farthest(dt1, dt2) + assert farthest == dt2 + + farthest = instance.farthest(dt2, dt1) + assert farthest == dt2 + + dts = [ + pendulum.datetime(2015, 5, 28, 16, 0, 0) + pendulum.duration(hours=x) + for x in range(4) + ] + farthest = instance.farthest(*dts) + assert farthest == dts[-1] + + farthest = instance.farthest(*(dts[::-1])) + assert farthest == dts[-1] + + f = pendulum.datetime(2010, 1, 1, 0, 0, 0) + assert f == instance.farthest(f, *(dts)) + + +def test_farthest_with_datetime(): + instance = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt1 = datetime(2015, 5, 28, 11, 0, 0, tzinfo=pendulum.UTC) + dt2 = datetime(2015, 5, 28, 14, 0, 0, tzinfo=pendulum.UTC) + farthest = instance.farthest(dt1, dt2) + assert_datetime(farthest, 2015, 5, 28, 14, 0, 0) + + dts = [ + pendulum.datetime(2015, 5, 28, 16, 0, 0) + pendulum.duration(hours=x) + for x in range(4) + ] + farthest = instance.farthest(dt1, dt2, *dts) + + assert_datetime(farthest, 2015, 5, 28, 19, 0, 0) + + +def test_farthest_with_equals(): + instance = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt1 = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt2 = pendulum.datetime(2015, 5, 28, 14, 0, 0) + farthest = instance.farthest(dt1, dt2) + assert farthest == dt2 + + dts = [ + pendulum.datetime(2015, 5, 28, 16, 0, 0) + pendulum.duration(hours=x) + for x in range(4) + ] + farthest = instance.farthest(dt1, dt2, *dts) + assert farthest == dts[-1] + + +def test_is_same_day(): + dt1 = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt2 = pendulum.datetime(2015, 5, 29, 12, 0, 0) + dt3 = pendulum.datetime(2015, 5, 28, 12, 0, 0) + dt4 = datetime(2015, 5, 28, 12, 0, 0, tzinfo=pendulum.UTC) + dt5 = datetime(2015, 5, 29, 12, 0, 0, tzinfo=pendulum.UTC) + + assert not dt1.is_same_day(dt2) + assert dt1.is_same_day(dt3) + assert dt1.is_same_day(dt4) + assert not dt1.is_same_day(dt5) + + +def test_comparison_to_unsupported(): + dt1 = pendulum.now() + + assert dt1 != "test" + assert dt1 not in ["test"] diff --git a/tests/datetime/test_construct.py b/tests/datetime/test_construct.py new file mode 100644 index 0000000..9488c08 --- /dev/null +++ b/tests/datetime/test_construct.py @@ -0,0 +1,182 @@ +from __future__ import annotations + +import os + +from datetime import datetime + +import pytest +import pytz + +from dateutil import tz + +import pendulum + +from pendulum import DateTime +from pendulum.tz import timezone +from pendulum.utils._compat import PYPY +from tests.conftest import assert_datetime + +if not PYPY: + import time_machine +else: + time_machine = None + + +@pytest.fixture(autouse=True) +def _setup(): + yield + + if os.getenv("TZ"): + del os.environ["TZ"] + + +def test_creates_an_instance_default_to_utcnow(): + now = pendulum.now("UTC") + p = pendulum.datetime( + now.year, now.month, now.day, now.hour, now.minute, now.second + ) + assert now.timezone_name == p.timezone_name + + assert_datetime(p, now.year, now.month, now.day, now.hour, now.minute, now.second) + + +def test_setting_timezone(): + tz = "Europe/London" + dtz = timezone(tz) + dt = datetime.utcnow() + offset = dtz.convert(dt).utcoffset().total_seconds() / 3600 + + p = pendulum.datetime(dt.year, dt.month, dt.day, tz=dtz) + assert p.timezone_name == tz + assert p.offset_hours == int(offset) + + +def test_setting_timezone_with_string(): + tz = "Europe/London" + dtz = timezone(tz) + dt = datetime.utcnow() + offset = dtz.convert(dt).utcoffset().total_seconds() / 3600 + + p = pendulum.datetime(dt.year, dt.month, dt.day, tz=tz) + assert p.timezone_name == tz + assert p.offset_hours == int(offset) + + +def test_today(): + today = pendulum.today() + assert isinstance(today, DateTime) + + +def test_tomorrow(): + now = pendulum.now().start_of("day") + tomorrow = pendulum.tomorrow() + assert isinstance(tomorrow, DateTime) + assert now.diff(tomorrow).in_days() == 1 + + +def test_yesterday(): + now = pendulum.now().start_of("day") + yesterday = pendulum.yesterday() + + assert isinstance(yesterday, DateTime) + assert now.diff(yesterday, False).in_days() == -1 + + +def test_instance_naive_datetime_defaults_to_utc(): + now = pendulum.instance(datetime.now()) + assert now.timezone_name == "UTC" + + +def test_instance_timezone_aware_datetime(): + now = pendulum.instance(datetime.now(timezone("Europe/Paris"))) + assert now.timezone_name == "Europe/Paris" + + +def test_instance_timezone_aware_datetime_pytz(): + now = pendulum.instance(datetime.now(pytz.timezone("Europe/Paris"))) + assert now.timezone_name == "Europe/Paris" + + +def test_instance_timezone_aware_datetime_any_tzinfo(): + dt = datetime(2016, 8, 7, 12, 34, 56, tzinfo=tz.gettz("Europe/Paris")) + now = pendulum.instance(dt) + assert now.timezone_name == "+02:00" + + +def test_now(): + now = pendulum.now("America/Toronto") + in_paris = pendulum.now("Europe/Paris") + + assert now.hour != in_paris.hour + + +if time_machine: + + @time_machine.travel("2016-03-27 00:30:00Z", tick=False) + def test_now_dst_off(): + utc = pendulum.now("UTC") + in_paris = pendulum.now("Europe/Paris") + in_paris_from_utc = utc.in_tz("Europe/Paris") + assert in_paris.hour == 1 + assert not in_paris.is_dst() + assert in_paris.isoformat() == in_paris_from_utc.isoformat() + + @time_machine.travel("2016-03-27 01:30:00Z", tick=False) + def test_now_dst_transitioning_on(): + utc = pendulum.now("UTC") + in_paris = pendulum.now("Europe/Paris") + in_paris_from_utc = utc.in_tz("Europe/Paris") + assert in_paris.hour == 3 + assert in_paris.is_dst() + assert in_paris.isoformat() == in_paris_from_utc.isoformat() + + @time_machine.travel("2016-10-30 00:30:00Z", tick=False) + def test_now_dst_on(): + utc = pendulum.now("UTC") + in_paris = pendulum.now("Europe/Paris") + in_paris_from_utc = utc.in_tz("Europe/Paris") + assert in_paris.hour == 2 + assert in_paris.is_dst() + assert in_paris.isoformat() == in_paris_from_utc.isoformat() + + @time_machine.travel("2016-10-30 01:30:00Z", tick=False) + def test_now_dst_transitioning_off(): + utc = pendulum.now("UTC") + in_paris = pendulum.now("Europe/Paris") + in_paris_from_utc = utc.in_tz("Europe/Paris") + assert in_paris.hour == 2 + assert not in_paris.is_dst() + assert in_paris.isoformat() == in_paris_from_utc.isoformat() + + +def test_now_with_fixed_offset(): + now = pendulum.now(6) + + assert now.timezone_name == "+06:00" + + +def test_create_with_no_transition_timezone(): + dt = pendulum.now("Etc/UTC") + + assert dt.timezone_name == "Etc/UTC" + + +def test_create_maintains_microseconds(): + d = pendulum.datetime(2016, 11, 12, 2, 9, 39, 594000, tz="America/Panama") + assert_datetime(d, 2016, 11, 12, 2, 9, 39, 594000) + + d = pendulum.datetime(2316, 11, 12, 2, 9, 39, 857, tz="America/Panama") + assert_datetime(d, 2316, 11, 12, 2, 9, 39, 857) + + +def test_second_inaccuracy_on_past_datetimes(): + dt = pendulum.datetime(1901, 12, 13, 0, 0, 0, 555555, tz="US/Central") + + assert_datetime(dt, 1901, 12, 13, 0, 0, 0, 555555) + + +def test_local(): + local = pendulum.local(2018, 2, 2, 12, 34, 56, 123456) + + assert_datetime(local, 2018, 2, 2, 12, 34, 56, 123456) + assert local.timezone_name == "America/Toronto" diff --git a/tests/datetime/test_create_from_timestamp.py b/tests/datetime/test_create_from_timestamp.py new file mode 100644 index 0000000..121a7c2 --- /dev/null +++ b/tests/datetime/test_create_from_timestamp.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +import pendulum + +from pendulum import timezone +from tests.conftest import assert_datetime + + +def test_create_from_timestamp_returns_pendulum(): + d = pendulum.from_timestamp(pendulum.datetime(1975, 5, 21, 22, 32, 5).timestamp()) + assert_datetime(d, 1975, 5, 21, 22, 32, 5) + assert d.timezone_name == "UTC" + + +def test_create_from_timestamp_with_timezone_string(): + d = pendulum.from_timestamp(0, "America/Toronto") + assert d.timezone_name == "America/Toronto" + assert_datetime(d, 1969, 12, 31, 19, 0, 0) + + +def test_create_from_timestamp_with_timezone(): + d = pendulum.from_timestamp(0, timezone("America/Toronto")) + assert d.timezone_name == "America/Toronto" + assert_datetime(d, 1969, 12, 31, 19, 0, 0) diff --git a/tests/datetime/test_day_of_week_modifiers.py b/tests/datetime/test_day_of_week_modifiers.py new file mode 100644 index 0000000..46de84e --- /dev/null +++ b/tests/datetime/test_day_of_week_modifiers.py @@ -0,0 +1,314 @@ +from __future__ import annotations + +import pytest + +import pendulum + +from pendulum.exceptions import PendulumException +from tests.conftest import assert_datetime + + +def test_start_of_week(): + d = pendulum.datetime(1980, 8, 7, 12, 11, 9).start_of("week") + assert_datetime(d, 1980, 8, 4, 0, 0, 0) + + +def test_start_of_week_from_week_start(): + d = pendulum.datetime(1980, 8, 4).start_of("week") + assert_datetime(d, 1980, 8, 4, 0, 0, 0) + + +def test_start_of_week_crossing_year_boundary(): + d = pendulum.datetime(2014, 1, 1).start_of("week") + assert_datetime(d, 2013, 12, 30, 0, 0, 0) + + +def test_end_of_week(): + d = pendulum.datetime(1980, 8, 7, 12, 11, 9).end_of("week") + assert_datetime(d, 1980, 8, 10, 23, 59, 59) + + +def test_end_of_week_from_week_end(): + d = pendulum.datetime(1980, 8, 10).end_of("week") + assert_datetime(d, 1980, 8, 10, 23, 59, 59) + + +def test_end_of_week_crossing_year_boundary(): + d = pendulum.datetime(2013, 12, 31).end_of("week") + assert_datetime(d, 2014, 1, 5, 23, 59, 59) + + +def test_next(): + d = pendulum.datetime(1975, 5, 21).next() + assert_datetime(d, 1975, 5, 28, 0, 0, 0) + + +def test_next_monday(): + d = pendulum.datetime(1975, 5, 21).next(pendulum.MONDAY) + assert_datetime(d, 1975, 5, 26, 0, 0, 0) + + +def test_next_saturday(): + d = pendulum.datetime(1975, 5, 21).next(6) + assert_datetime(d, 1975, 5, 24, 0, 0, 0) + + +def test_next_keep_time(): + d = pendulum.datetime(1975, 5, 21, 12).next() + assert_datetime(d, 1975, 5, 28, 0, 0, 0) + + d = pendulum.datetime(1975, 5, 21, 12).next(keep_time=True) + assert_datetime(d, 1975, 5, 28, 12, 0, 0) + + +def test_next_invalid(): + dt = pendulum.datetime(1975, 5, 21, 12) + + with pytest.raises(ValueError): + dt.next(7) + + +def test_previous(): + d = pendulum.datetime(1975, 5, 21).previous() + assert_datetime(d, 1975, 5, 14, 0, 0, 0) + + +def test_previous_monday(): + d = pendulum.datetime(1975, 5, 21).previous(pendulum.MONDAY) + assert_datetime(d, 1975, 5, 19, 0, 0, 0) + + +def test_previous_saturday(): + d = pendulum.datetime(1975, 5, 21).previous(6) + assert_datetime(d, 1975, 5, 17, 0, 0, 0) + + +def test_previous_keep_time(): + d = pendulum.datetime(1975, 5, 21, 12).previous() + assert_datetime(d, 1975, 5, 14, 0, 0, 0) + + d = pendulum.datetime(1975, 5, 21, 12).previous(keep_time=True) + assert_datetime(d, 1975, 5, 14, 12, 0, 0) + + +def test_previous_invalid(): + dt = pendulum.datetime(1975, 5, 21, 12) + + with pytest.raises(ValueError): + dt.previous(7) + + +def test_first_day_of_month(): + d = pendulum.datetime(1975, 11, 21).first_of("month") + assert_datetime(d, 1975, 11, 1, 0, 0, 0) + + +def test_first_wednesday_of_month(): + d = pendulum.datetime(1975, 11, 21).first_of("month", pendulum.WEDNESDAY) + assert_datetime(d, 1975, 11, 5, 0, 0, 0) + + +def test_first_friday_of_month(): + d = pendulum.datetime(1975, 11, 21).first_of("month", 5) + assert_datetime(d, 1975, 11, 7, 0, 0, 0) + + +def test_last_day_of_month(): + d = pendulum.datetime(1975, 12, 5).last_of("month") + assert_datetime(d, 1975, 12, 31, 0, 0, 0) + + +def test_last_tuesday_of_month(): + d = pendulum.datetime(1975, 12, 1).last_of("month", pendulum.TUESDAY) + assert_datetime(d, 1975, 12, 30, 0, 0, 0) + + +def test_last_friday_of_month(): + d = pendulum.datetime(1975, 12, 5).last_of("month", 5) + assert_datetime(d, 1975, 12, 26, 0, 0, 0) + + +def test_nth_of_month_outside_scope(): + d = pendulum.datetime(1975, 6, 5) + + with pytest.raises(PendulumException): + d.nth_of("month", 6, pendulum.MONDAY) + + +def test_nth_of_month_outside_year(): + d = pendulum.datetime(1975, 12, 5) + + with pytest.raises(PendulumException): + d.nth_of("month", 55, pendulum.MONDAY) + + +def test_nth_of_month_first(): + d = pendulum.datetime(1975, 12, 5).nth_of("month", 1, pendulum.MONDAY) + + assert_datetime(d, 1975, 12, 1, 0, 0, 0) + + +def test_2nd_monday_of_month(): + d = pendulum.datetime(1975, 12, 5).nth_of("month", 2, pendulum.MONDAY) + + assert_datetime(d, 1975, 12, 8, 0, 0, 0) + + +def test_3rd_wednesday_of_month(): + d = pendulum.datetime(1975, 12, 5).nth_of("month", 3, 3) + + assert_datetime(d, 1975, 12, 17, 0, 0, 0) + + +def test_first_day_of_quarter(): + d = pendulum.datetime(1975, 11, 21).first_of("quarter") + assert_datetime(d, 1975, 10, 1, 0, 0, 0) + + +def test_first_wednesday_of_quarter(): + d = pendulum.datetime(1975, 11, 21).first_of("quarter", pendulum.WEDNESDAY) + assert_datetime(d, 1975, 10, 1, 0, 0, 0) + + +def test_first_friday_of_quarter(): + d = pendulum.datetime(1975, 11, 21).first_of("quarter", 5) + assert_datetime(d, 1975, 10, 3, 0, 0, 0) + + +def test_first_of_quarter_from_a_day_that_will_not_exist_in_the_first_month(): + d = pendulum.datetime(2014, 5, 31).first_of("quarter") + assert_datetime(d, 2014, 4, 1, 0, 0, 0) + + +def test_last_day_of_quarter(): + d = pendulum.datetime(1975, 8, 5).last_of("quarter") + assert_datetime(d, 1975, 9, 30, 0, 0, 0) + + +def test_last_tuesday_of_quarter(): + d = pendulum.datetime(1975, 8, 5).last_of("quarter", pendulum.TUESDAY) + assert_datetime(d, 1975, 9, 30, 0, 0, 0) + + +def test_last_friday_of_quarter(): + d = pendulum.datetime(1975, 8, 5).last_of("quarter", pendulum.FRIDAY) + assert_datetime(d, 1975, 9, 26, 0, 0, 0) + + +def test_last_day_of_quarter_that_will_not_exist_in_the_last_month(): + d = pendulum.datetime(2014, 5, 31).last_of("quarter") + assert_datetime(d, 2014, 6, 30, 0, 0, 0) + + +def test_nth_of_quarter_outside_scope(): + d = pendulum.datetime(1975, 1, 5) + + with pytest.raises(PendulumException): + d.nth_of("quarter", 20, pendulum.MONDAY) + + +def test_nth_of_quarter_outside_year(): + d = pendulum.datetime(1975, 1, 5) + + with pytest.raises(PendulumException): + d.nth_of("quarter", 55, pendulum.MONDAY) + + +def test_nth_of_quarter_first(): + d = pendulum.datetime(1975, 12, 5).nth_of("quarter", 1, pendulum.MONDAY) + + assert_datetime(d, 1975, 10, 6, 0, 0, 0) + + +def test_nth_of_quarter_from_a_day_that_will_not_exist_in_the_first_month(): + d = pendulum.datetime(2014, 5, 31).nth_of("quarter", 2, pendulum.MONDAY) + assert_datetime(d, 2014, 4, 14, 0, 0, 0) + + +def test_2nd_monday_of_quarter(): + d = pendulum.datetime(1975, 8, 5).nth_of("quarter", 2, pendulum.MONDAY) + assert_datetime(d, 1975, 7, 14, 0, 0, 0) + + +def test_3rd_wednesday_of_quarter(): + d = pendulum.datetime(1975, 8, 5).nth_of("quarter", 3, 3) + assert_datetime(d, 1975, 7, 16, 0, 0, 0) + + +def test_first_day_of_year(): + d = pendulum.datetime(1975, 11, 21).first_of("year") + assert_datetime(d, 1975, 1, 1, 0, 0, 0) + + +def test_first_wednesday_of_year(): + d = pendulum.datetime(1975, 11, 21).first_of("year", pendulum.WEDNESDAY) + assert_datetime(d, 1975, 1, 1, 0, 0, 0) + + +def test_first_friday_of_year(): + d = pendulum.datetime(1975, 11, 21).first_of("year", 5) + assert_datetime(d, 1975, 1, 3, 0, 0, 0) + + +def test_last_day_of_year(): + d = pendulum.datetime(1975, 8, 5).last_of("year") + assert_datetime(d, 1975, 12, 31, 0, 0, 0) + + +def test_last_tuesday_of_year(): + d = pendulum.datetime(1975, 8, 5).last_of("year", pendulum.TUESDAY) + assert_datetime(d, 1975, 12, 30, 0, 0, 0) + + +def test_last_friday_of_year(): + d = pendulum.datetime(1975, 8, 5).last_of("year", 5) + assert_datetime(d, 1975, 12, 26, 0, 0, 0) + + +def test_nth_of_year_outside_scope(): + d = pendulum.datetime(1975, 1, 5) + + with pytest.raises(PendulumException): + d.nth_of("year", 55, pendulum.MONDAY) + + +def test_nth_of_year_first(): + d = pendulum.datetime(1975, 12, 5).nth_of("year", 1, pendulum.MONDAY) + + assert_datetime(d, 1975, 1, 6, 0, 0, 0) + + +def test_2nd_monday_of_year(): + d = pendulum.datetime(1975, 8, 5).nth_of("year", 2, pendulum.MONDAY) + assert_datetime(d, 1975, 1, 13, 0, 0, 0) + + +def test_2rd_wednesday_of_year(): + d = pendulum.datetime(1975, 8, 5).nth_of("year", 3, pendulum.WEDNESDAY) + assert_datetime(d, 1975, 1, 15, 0, 0, 0) + + +def test_7th_thursday_of_year(): + d = pendulum.datetime(1975, 8, 31).nth_of("year", 7, pendulum.THURSDAY) + assert_datetime(d, 1975, 2, 13, 0, 0, 0) + + +def test_first_of_invalid_unit(): + d = pendulum.datetime(1975, 8, 5) + + with pytest.raises(ValueError): + d.first_of("invalid") + + +def test_last_of_invalid_unit(): + d = pendulum.datetime(1975, 8, 5) + + with pytest.raises(ValueError): + d.last_of("invalid") + + +def test_nth_of_invalid_unit(): + d = pendulum.datetime(1975, 8, 5) + + with pytest.raises(ValueError): + d.nth_of("invalid", 3, pendulum.MONDAY) diff --git a/tests/datetime/test_diff.py b/tests/datetime/test_diff.py new file mode 100644 index 0000000..7a31507 --- /dev/null +++ b/tests/datetime/test_diff.py @@ -0,0 +1,880 @@ +from __future__ import annotations + +from datetime import datetime + +import pytest + +import pendulum + + +def test_diff_in_years_positive(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(years=1)).in_years() == 1 + + +def test_diff_in_years_negative_with_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(years=1), False).in_years() == -1 + + +def test_diff_in_years_negative_no_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(years=1)).in_years() == 1 + + +def test_diff_in_years_vs_default_now(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(years=1).diff().in_years() == 1 + + +def test_diff_in_years_ensure_is_truncated(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(years=1).add(months=7)).in_years() == 1 + + +def test_diff_in_months_positive(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(years=1).add(months=1)).in_months() == 13 + + +def test_diff_in_months_negative_with_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(years=1).add(months=1), False).in_months() == -11 + + +def test_diff_in_months_negative_no_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(years=1).add(months=1)).in_months() == 11 + + +def test_diff_in_months_vs_default_now(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(years=1).diff().in_months() == 12 + + +def test_diff_in_months_ensure_is_truncated(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(months=1).add(days=16)).in_months() == 1 + + +def test_diff_in_days_positive(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(years=1)).in_days() == 366 + + +def test_diff_in_days_negative_with_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(years=1), False).in_days() == -365 + + +def test_diff_in_days_negative_no_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(years=1)).in_days() == 365 + + +def test_diff_in_days_vs_default_now(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(weeks=1).diff().in_days() == 7 + + +def test_diff_in_days_ensure_is_truncated(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(days=1).add(hours=13)).in_days() == 1 + + +def test_diff_in_weeks_positive(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(years=1)).in_weeks() == 52 + + +def test_diff_in_weeks_negative_with_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(years=1), False).in_weeks() == -52 + + +def test_diff_in_weeks_negative_no_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(years=1)).in_weeks() == 52 + + +def test_diff_in_weeks_vs_default_now(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(weeks=1).diff().in_weeks() == 1 + + +def test_diff_in_weeks_ensure_is_truncated(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(weeks=1).subtract(days=1)).in_weeks() == 0 + + +def test_diff_in_hours_positive(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(days=1).add(hours=2)).in_hours() == 26 + + +def test_diff_in_hours_negative_with_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(days=1).add(hours=2), False).in_hours() == -22 + + +def test_diff_in_hours_negative_no_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(days=1).add(hours=2)).in_hours() == 22 + + +def test_diff_in_hours_vs_default_now(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 15), freeze=True): + assert pendulum.now().subtract(days=2).diff().in_hours() == 48 + + +def test_diff_in_hours_ensure_is_truncated(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(hours=1).add(minutes=31)).in_hours() == 1 + + +def test_diff_in_minutes_positive(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(hours=1).add(minutes=2)).in_minutes() == 62 + + +def test_diff_in_minutes_positive_big(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(hours=25).add(minutes=2)).in_minutes() == 1502 + + +def test_diff_in_minutes_negative_with_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(hours=1).add(minutes=2), False).in_minutes() == -58 + + +def test_diff_in_minutes_negative_no_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(hours=1).add(minutes=2)).in_minutes() == 58 + + +def test_diff_in_minutes_vs_default_now(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(hours=1).diff().in_minutes() == 60 + + +def test_diff_in_minutes_ensure_is_truncated(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(minutes=1).add(seconds=59)).in_minutes() == 1 + + +def test_diff_in_seconds_positive(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(minutes=1).add(seconds=2)).in_seconds() == 62 + + +def test_diff_in_seconds_positive_big(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(hours=2).add(seconds=2)).in_seconds() == 7202 + + +def test_diff_in_seconds_negative_with_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(minutes=1).add(seconds=2), False).in_seconds() == -58 + + +def test_diff_in_seconds_negative_no_sign(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.subtract(minutes=1).add(seconds=2)).in_seconds() == 58 + + +def test_diff_in_seconds_vs_default_now(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(hours=1).diff().in_seconds() == 3600 + + +def test_diff_in_seconds_ensure_is_truncated(): + dt = pendulum.datetime(2000, 1, 1) + assert dt.diff(dt.add(seconds=1.9)).in_seconds() == 1 + + +def test_diff_in_seconds_with_timezones(): + dt_ottawa = pendulum.datetime(2000, 1, 1, 13, tz="America/Toronto") + dt_vancouver = pendulum.datetime(2000, 1, 1, 13, tz="America/Vancouver") + assert dt_ottawa.diff(dt_vancouver).in_seconds() == 3 * 60 * 60 + + +def test_diff_for_humans_now_and_second(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().diff_for_humans() == "a few seconds ago" + + +def test_diff_for_humans_now_and_second_with_timezone(): + van_now = pendulum.now("America/Vancouver") + here_now = van_now.in_timezone(pendulum.now().timezone) + + with pendulum.travel_to(here_now, freeze=True): + assert here_now.diff_for_humans() == "a few seconds ago" + + +def test_diff_for_humans_now_and_seconds(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().subtract(seconds=2).diff_for_humans() == "a few seconds ago" + ) + + +def test_diff_for_humans_now_and_nearly_minute(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(seconds=59).diff_for_humans() == "59 seconds ago" + + +def test_diff_for_humans_now_and_minute(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(minutes=1).diff_for_humans() == "1 minute ago" + + +def test_diff_for_humans_now_and_minutes(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(minutes=2).diff_for_humans() == "2 minutes ago" + + +def test_diff_for_humans_now_and_nearly_hour(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(minutes=59).diff_for_humans() == "59 minutes ago" + + +def test_diff_for_humans_now_and_hour(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(hours=1).diff_for_humans() == "1 hour ago" + + +def test_diff_for_humans_now_and_hours(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(hours=2).diff_for_humans() == "2 hours ago" + + +def test_diff_for_humans_now_and_nearly_day(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(hours=23).diff_for_humans() == "23 hours ago" + + +def test_diff_for_humans_now_and_day(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(days=1).diff_for_humans() == "1 day ago" + + +def test_diff_for_humans_now_and_days(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(days=2).diff_for_humans() == "2 days ago" + + +def test_diff_for_humans_now_and_nearly_week(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(days=6).diff_for_humans() == "6 days ago" + + +def test_diff_for_humans_now_and_week(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(weeks=1).diff_for_humans() == "1 week ago" + + +def test_diff_for_humans_now_and_weeks(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(weeks=2).diff_for_humans() == "2 weeks ago" + + +def test_diff_for_humans_now_and_nearly_month(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(weeks=3).diff_for_humans() == "3 weeks ago" + + +def test_diff_for_humans_now_and_month(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(weeks=4).diff_for_humans() == "4 weeks ago" + assert pendulum.now().subtract(months=1).diff_for_humans() == "1 month ago" + + +def test_diff_for_humans_now_and_months(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(months=2).diff_for_humans() == "2 months ago" + + +def test_diff_for_humans_now_and_nearly_year(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(months=11).diff_for_humans() == "11 months ago" + + +def test_diff_for_humans_now_and_year(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(years=1).diff_for_humans() == "1 year ago" + + +def test_diff_for_humans_now_and_years(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().subtract(years=2).diff_for_humans() == "2 years ago" + + +def test_diff_for_humans_now_and_future_second(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(seconds=1).diff_for_humans() == "in a few seconds" + + +def test_diff_for_humans_now_and_future_seconds(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(seconds=2).diff_for_humans() == "in a few seconds" + + +def test_diff_for_humans_now_and_nearly_future_minute(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(seconds=59).diff_for_humans() == "in 59 seconds" + + +def test_diff_for_humans_now_and_future_minute(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(minutes=1).diff_for_humans() == "in 1 minute" + + +def test_diff_for_humans_now_and_future_minutes(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(minutes=2).diff_for_humans() == "in 2 minutes" + + +def test_diff_for_humans_now_and_nearly_future_hour(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(minutes=59).diff_for_humans() == "in 59 minutes" + + +def test_diff_for_humans_now_and_future_hour(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(hours=1).diff_for_humans() == "in 1 hour" + + +def test_diff_for_humans_now_and_future_hours(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(hours=2).diff_for_humans() == "in 2 hours" + + +def test_diff_for_humans_now_and_nearly_future_day(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(hours=23).diff_for_humans() == "in 23 hours" + + +def test_diff_for_humans_now_and_future_day(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(days=1).diff_for_humans() == "in 1 day" + + +def test_diff_for_humans_now_and_future_days(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(days=2).diff_for_humans() == "in 2 days" + + +def test_diff_for_humans_now_and_nearly_future_week(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(days=6).diff_for_humans() == "in 6 days" + + +def test_diff_for_humans_now_and_future_week(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(weeks=1).diff_for_humans() == "in 1 week" + + +def test_diff_for_humans_now_and_future_weeks(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(weeks=2).diff_for_humans() == "in 2 weeks" + + +def test_diff_for_humans_now_and_nearly_future_month(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(weeks=3).diff_for_humans() == "in 3 weeks" + + +def test_diff_for_humans_now_and_future_month(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(weeks=4).diff_for_humans() == "in 4 weeks" + assert pendulum.now().add(months=1).diff_for_humans() == "in 1 month" + + +def test_diff_for_humans_now_and_future_months(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(months=2).diff_for_humans() == "in 2 months" + + +def test_diff_for_humans_now_and_nearly_future_year(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(months=11).diff_for_humans() == "in 11 months" + + +def test_diff_for_humans_now_and_future_year(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(years=1).diff_for_humans() == "in 1 year" + + +def test_diff_for_humans_now_and_future_years(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert pendulum.now().add(years=2).diff_for_humans() == "in 2 years" + + +def test_diff_for_humans_other_and_second(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(seconds=1)) + == "a few seconds before" + ) + + +def test_diff_for_humans_other_and_seconds(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(seconds=2)) + == "a few seconds before" + ) + + +def test_diff_for_humans_other_and_nearly_minute(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(seconds=59)) + == "59 seconds before" + ) + + +def test_diff_for_humans_other_and_minute(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(minutes=1)) + == "1 minute before" + ) + + +def test_diff_for_humans_other_and_minutes(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(minutes=2)) + == "2 minutes before" + ) + + +def test_diff_for_humans_other_and_nearly_hour(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(minutes=59)) + == "59 minutes before" + ) + + +def test_diff_for_humans_other_and_hour(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(hours=1)) + == "1 hour before" + ) + + +def test_diff_for_humans_other_and_hours(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(hours=2)) + == "2 hours before" + ) + + +def test_diff_for_humans_other_and_nearly_day(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(hours=23)) + == "23 hours before" + ) + + +def test_diff_for_humans_other_and_day(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(days=1)) == "1 day before" + ) + + +def test_diff_for_humans_other_and_days(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(days=2)) + == "2 days before" + ) + + +def test_diff_for_humans_other_and_nearly_week(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(days=6)) + == "6 days before" + ) + + +def test_diff_for_humans_other_and_week(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(weeks=1)) + == "1 week before" + ) + + +def test_diff_for_humans_other_and_weeks(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(weeks=2)) + == "2 weeks before" + ) + + +def test_diff_for_humans_other_and_nearly_month(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(weeks=3)) + == "3 weeks before" + ) + + +def test_diff_for_humans_other_and_month(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(weeks=4)) + == "4 weeks before" + ) + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(months=1)) + == "1 month before" + ) + + +def test_diff_for_humans_other_and_months(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(months=2)) + == "2 months before" + ) + + +def test_diff_for_humans_other_and_nearly_year(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(months=11)) + == "11 months before" + ) + + +def test_diff_for_humans_other_and_year(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(years=1)) + == "1 year before" + ) + + +def test_diff_for_humans_other_and_years(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(years=2)) + == "2 years before" + ) + + +def test_diff_for_humans_other_and_future_second(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(seconds=1)) + == "a few seconds after" + ) + + +def test_diff_for_humans_other_and_future_seconds(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(seconds=2)) + == "a few seconds after" + ) + + +def test_diff_for_humans_other_and_nearly_future_minute(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(seconds=59)) + == "59 seconds after" + ) + + +def test_diff_for_humans_other_and_future_minute(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(minutes=1)) + == "1 minute after" + ) + + +def test_diff_for_humans_other_and_future_minutes(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(minutes=2)) + == "2 minutes after" + ) + + +def test_diff_for_humans_other_and_nearly_future_hour(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(minutes=59)) + == "59 minutes after" + ) + + +def test_diff_for_humans_other_and_future_hour(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(hours=1)) + == "1 hour after" + ) + + +def test_diff_for_humans_other_and_future_hours(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(hours=2)) + == "2 hours after" + ) + + +def test_diff_for_humans_other_and_nearly_future_day(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(hours=23)) + == "23 hours after" + ) + + +def test_diff_for_humans_other_and_future_day(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(days=1)) + == "1 day after" + ) + + +def test_diff_for_humans_other_and_future_days(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(days=2)) + == "2 days after" + ) + + +def test_diff_for_humans_other_and_nearly_future_week(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(days=6)) + == "6 days after" + ) + + +def test_diff_for_humans_other_and_future_week(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(weeks=1)) + == "1 week after" + ) + + +def test_diff_for_humans_other_and_future_weeks(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(weeks=2)) + == "2 weeks after" + ) + + +def test_diff_for_humans_other_and_nearly_future_month(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(weeks=3)) + == "3 weeks after" + ) + + +def test_diff_for_humans_other_and_future_month(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(weeks=4)) + == "4 weeks after" + ) + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(months=1)) + == "1 month after" + ) + + +def test_diff_for_humans_other_and_future_months(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(months=2)) + == "2 months after" + ) + + +def test_diff_for_humans_other_and_nearly_future_year(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(months=11)) + == "11 months after" + ) + + +def test_diff_for_humans_other_and_future_year(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(years=1)) + == "1 year after" + ) + + +def test_diff_for_humans_other_and_future_years(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(years=2)) + == "2 years after" + ) + + +def test_diff_for_humans_absolute_seconds(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(seconds=59), True) + == "59 seconds" + ) + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(seconds=59), True) + == "59 seconds" + ) + + +def test_diff_for_humans_absolute_minutes(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(minutes=30), True) + == "30 minutes" + ) + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(minutes=30), True) + == "30 minutes" + ) + + +def test_diff_for_humans_absolute_hours(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(hours=3), True) + == "3 hours" + ) + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(hours=3), True) + == "3 hours" + ) + + +def test_diff_for_humans_absolute_days(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(days=2), True) + == "2 days" + ) + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(days=2), True) == "2 days" + ) + + +def test_diff_for_humans_absolute_weeks(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(weeks=2), True) + == "2 weeks" + ) + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(weeks=2), True) + == "2 weeks" + ) + + +def test_diff_for_humans_absolute_months(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(months=2), True) + == "2 months" + ) + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(months=2), True) + == "2 months" + ) + + +def test_diff_for_humans_absolute_years(): + with pendulum.travel_to(pendulum.datetime(2012, 1, 1, 1, 2, 3), freeze=True): + assert ( + pendulum.now().diff_for_humans(pendulum.now().subtract(years=1), True) + == "1 year" + ) + assert ( + pendulum.now().diff_for_humans(pendulum.now().add(years=1), True) + == "1 year" + ) + + +def test_diff_for_humans_accuracy(): + now = pendulum.now("utc") + + with pendulum.travel_to(now.add(microseconds=200), freeze=True): + assert now.add(years=1).diff_for_humans(absolute=True) == "1 year" + assert now.add(months=11).diff_for_humans(absolute=True) == "11 months" + assert now.add(days=27).diff_for_humans(absolute=True) == "4 weeks" + assert now.add(years=1, months=3).diff_for_humans(absolute=True) == "1 year" + assert now.add(years=1, months=8).diff_for_humans(absolute=True) == "2 years" + + # DST + now = pendulum.datetime(2017, 3, 7, tz="America/Toronto") + with pendulum.travel_to(now, freeze=True): + assert now.add(days=6).diff_for_humans(absolute=True) == "6 days" + + +def test_subtraction(): + d = pendulum.naive(2016, 7, 5, 12, 32, 25, 0) + future_dt = datetime(2016, 7, 5, 13, 32, 25, 0) + future = d.add(hours=1) + + assert (future - d).total_seconds() == 3600 + assert (future_dt - d).total_seconds() == 3600 + + +def test_subtraction_aware_naive(): + dt = pendulum.datetime(2016, 7, 5, 12, 32, 25, 0) + future_dt = datetime(2016, 7, 5, 13, 32, 25, 0) + + with pytest.raises(TypeError): + future_dt - dt + + future_dt = pendulum.naive(2016, 7, 5, 13, 32, 25, 0) + + with pytest.raises(TypeError): + future_dt - dt + + +def test_subtraction_with_timezone(): + dt = pendulum.datetime(2013, 3, 31, 1, 59, 59, 999999, tz="Europe/Paris") + post = dt.add(microseconds=1) + + assert (post - dt).total_seconds() == 1e-06 + + dt = pendulum.datetime( + 2013, + 10, + 27, + 2, + 59, + 59, + 999999, + tz="Europe/Paris", + fold=0, + ) + post = dt.add(microseconds=1) + + assert (post - dt).total_seconds() == 1e-06 diff --git a/tests/datetime/test_fluent_setters.py b/tests/datetime/test_fluent_setters.py new file mode 100644 index 0000000..cedbd26 --- /dev/null +++ b/tests/datetime/test_fluent_setters.py @@ -0,0 +1,181 @@ +from __future__ import annotations + +from datetime import datetime + +import pendulum + +from tests.conftest import assert_datetime + + +def test_fluid_year_setter(): + d = pendulum.now() + new = d.set(year=1995) + assert isinstance(new, datetime) + assert new.year == 1995 + assert d.year != new.year + + +def test_fluid_month_setter(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20) + new = d.set(month=11) + assert isinstance(new, datetime) + assert new.month == 11 + assert d.month == 7 + + +def test_fluid_day_setter(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20) + new = d.set(day=9) + assert isinstance(new, datetime) + assert new.day == 9 + assert d.day == 2 + + +def test_fluid_hour_setter(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20) + new = d.set(hour=5) + assert isinstance(new, datetime) + assert new.hour == 5 + assert d.hour == 0 + + +def test_fluid_minute_setter(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20) + new = d.set(minute=32) + assert isinstance(new, datetime) + assert new.minute == 32 + assert d.minute == 41 + + +def test_fluid_second_setter(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20) + new = d.set(second=49) + assert isinstance(new, datetime) + assert new.second == 49 + assert d.second == 20 + + +def test_fluid_microsecond_setter(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20, 123456) + new = d.set(microsecond=987654) + assert isinstance(new, datetime) + assert new.microsecond == 987654 + assert d.microsecond == 123456 + + +def test_fluid_setter_keeps_timezone(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20, 123456, tz="Europe/Paris") + new = d.set(microsecond=987654) + assert_datetime(new, 2016, 7, 2, 0, 41, 20, 987654) + + +def test_fluid_timezone_setter(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20) + new = d.set(tz="Europe/Paris") + assert isinstance(new, datetime) + assert new.timezone_name == "Europe/Paris" + assert new.tzinfo.name == "Europe/Paris" + + +def test_fluid_on(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20) + new = d.on(1995, 11, 9) + assert isinstance(new, datetime) + assert new.year == 1995 + assert new.month == 11 + assert new.day == 9 + assert d.year == 2016 + assert d.month == 7 + assert d.day == 2 + + +def test_fluid_on_with_transition(): + d = pendulum.datetime(2013, 3, 31, 0, 0, 0, 0, tz="Europe/Paris") + new = d.on(2013, 4, 1) + assert isinstance(new, datetime) + assert new.year == 2013 + assert new.month == 4 + assert new.day == 1 + assert new.offset == 7200 + assert d.year == 2013 + assert d.month == 3 + assert d.day == 31 + assert d.offset == 3600 + + +def test_fluid_at(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20) + new = d.at(5, 32, 49, 123456) + assert isinstance(new, datetime) + assert new.hour == 5 + assert new.minute == 32 + assert new.second == 49 + assert new.microsecond == 123456 + assert d.hour == 0 + assert d.minute == 41 + assert d.second == 20 + assert d.microsecond == 0 + + +def test_fluid_at_partial(): + d = pendulum.datetime(2016, 7, 2, 0, 41, 20) + new = d.at(10) + + assert_datetime(new, 2016, 7, 2, 10, 0, 0, 0) + + new = d.at(10, 30) + + assert_datetime(new, 2016, 7, 2, 10, 30, 0, 0) + + new = d.at(10, 30, 45) + + assert_datetime(new, 2016, 7, 2, 10, 30, 45, 0) + + +def test_fluid_at_with_transition(): + d = pendulum.datetime(2013, 3, 31, 0, 0, 0, 0, tz="Europe/Paris") + new = d.at(2, 30, 0) + assert isinstance(new, datetime) + assert new.hour == 3 + assert new.minute == 30 + assert new.second == 0 + + +def test_replace_tzinfo_dst_off(): + d = pendulum.datetime(2016, 3, 27, 0, 30) # 30 min before DST turning on + new = d.replace(tzinfo=pendulum.timezone("Europe/Paris")) + + assert_datetime(new, 2016, 3, 27, 0, 30) + assert not new.is_dst() + assert new.offset == 3600 + assert new.timezone_name == "Europe/Paris" + + +def test_replace_tzinfo_dst_transitioning_on(): + d = pendulum.datetime(2016, 3, 27, 1, 30) # In middle of turning on + new = d.replace(tzinfo=pendulum.timezone("Europe/Paris")) + + assert_datetime(new, 2016, 3, 27, 1, 30) + assert not new.is_dst() + assert new.offset == 3600 + assert new.timezone_name == "Europe/Paris" + + +def test_replace_tzinfo_dst_on(): + d = pendulum.datetime(2016, 10, 30, 0, 30) # 30 min before DST turning off + new = d.replace(tzinfo=pendulum.timezone("Europe/Paris")) + + assert_datetime(new, 2016, 10, 30, 0, 30) + assert new.is_dst() + assert new.offset == 7200 + assert new.timezone_name == "Europe/Paris" + + +def test_replace_tzinfo_dst_transitioning_off(): + d = pendulum.datetime(2016, 10, 30, 1, 30) # In the middle of turning off + new = d.replace(tzinfo=pendulum.timezone("Europe/Paris")) + + assert_datetime(new, 2016, 10, 30, 1, 30) + assert new.is_dst() + assert new.offset == 7200 + assert new.timezone_name == "Europe/Paris" diff --git a/tests/datetime/test_from_format.py b/tests/datetime/test_from_format.py new file mode 100644 index 0000000..10c4a23 --- /dev/null +++ b/tests/datetime/test_from_format.py @@ -0,0 +1,203 @@ +from __future__ import annotations + +import pytest + +import pendulum + +from tests.conftest import assert_datetime + + +def test_from_format_returns_datetime(): + d = pendulum.from_format("1975-05-21 22:32:11", "YYYY-MM-DD HH:mm:ss") + assert_datetime(d, 1975, 5, 21, 22, 32, 11) + assert isinstance(d, pendulum.DateTime) + assert d.timezone_name == "UTC" + + +def test_from_format_rejects_extra_text(): + with pytest.raises(ValueError): + pendulum.from_format("1975-05-21 22:32:11 extra text", "YYYY-MM-DD HH:mm:ss") + + +def test_from_format_with_timezone_string(): + d = pendulum.from_format( + "1975-05-21 22:32:11", "YYYY-MM-DD HH:mm:ss", tz="Europe/London" + ) + assert_datetime(d, 1975, 5, 21, 22, 32, 11) + assert d.timezone_name == "Europe/London" + + +def test_from_format_with_timezone(): + d = pendulum.from_format( + "1975-05-21 22:32:11", + "YYYY-MM-DD HH:mm:ss", + tz=pendulum.timezone("Europe/London"), + ) + assert_datetime(d, 1975, 5, 21, 22, 32, 11) + assert d.timezone_name == "Europe/London" + + +def test_from_format_with_square_bracket_in_timezone(): + with pytest.raises(ValueError, match="^String does not match format"): + pendulum.from_format( + "1975-05-21 22:32:11 Eu[rope/London", + "YYYY-MM-DD HH:mm:ss z", + ) + + +def test_from_format_with_escaped_elements(): + d = pendulum.from_format("1975-05-21T22:32:11+00:00", "YYYY-MM-DD[T]HH:mm:ssZ") + assert_datetime(d, 1975, 5, 21, 22, 32, 11) + assert d.timezone_name == "+00:00" + + +def test_from_format_with_escaped_elements_valid_tokens(): + d = pendulum.from_format("1975-05-21T22:32:11.123Z", "YYYY-MM-DD[T]HH:mm:ss.SSS[Z]") + assert_datetime(d, 1975, 5, 21, 22, 32, 11) + assert d.timezone_name == "UTC" + + +def test_from_format_with_millis(): + d = pendulum.from_format("1975-05-21 22:32:11.123456", "YYYY-MM-DD HH:mm:ss.SSSSSS") + assert_datetime(d, 1975, 5, 21, 22, 32, 11, 123456) + + +def test_from_format_with_padded_day(): + d = pendulum.from_format("Apr 2 12:00:00 2020 GMT", "MMM DD HH:mm:ss YYYY z") + assert_datetime(d, 2020, 4, 2, 12) + + +def test_from_format_with_invalid_padded_day(): + with pytest.raises(ValueError): + pendulum.from_format("Apr 2 12:00:00 2020 GMT", "MMM DD HH:mm:ss YYYY z") + + +@pytest.mark.parametrize( + "text,fmt,expected,now", + [ + ("2014-4", "YYYY-Q", "2014-10-01T00:00:00+00:00", None), + ("12-02-1999", "MM-DD-YYYY", "1999-12-02T00:00:00+00:00", None), + ("12-02-1999", "DD-MM-YYYY", "1999-02-12T00:00:00+00:00", None), + ("12/02/1999", "DD/MM/YYYY", "1999-02-12T00:00:00+00:00", None), + ("12_02_1999", "DD_MM_YYYY", "1999-02-12T00:00:00+00:00", None), + ("12:02:1999", "DD:MM:YYYY", "1999-02-12T00:00:00+00:00", None), + ("2-2-99", "D-M-YY", "2099-02-02T00:00:00+00:00", None), + ("2-2-99", "D-M-YY", "1999-02-02T00:00:00+00:00", "1990-01-01"), + ("99", "YY", "2099-01-01T00:00:00+00:00", None), + ("300-1999", "DDD-YYYY", "1999-10-27T00:00:00+00:00", None), + ("12-02-1999 2:45:10", "DD-MM-YYYY h:m:s", "1999-02-12T02:45:10+00:00", None), + ("12-02-1999 12:45:10", "DD-MM-YYYY h:m:s", "1999-02-12T12:45:10+00:00", None), + ("12:00:00", "HH:mm:ss", "2015-11-12T12:00:00+00:00", None), + ("12:30:00", "HH:mm:ss", "2015-11-12T12:30:00+00:00", None), + ("00:00:00", "HH:mm:ss", "2015-11-12T00:00:00+00:00", None), + ("00:30:00 1", "HH:mm:ss S", "2015-11-12T00:30:00.100000+00:00", None), + ("00:30:00 12", "HH:mm:ss SS", "2015-11-12T00:30:00.120000+00:00", None), + ("00:30:00 123", "HH:mm:ss SSS", "2015-11-12T00:30:00.123000+00:00", None), + ("1234567890", "X", "2009-02-13T23:31:30+00:00", None), + ("1234567890123", "x", "2009-02-13T23:31:30.123000+00:00", None), + ("2016-10-06", "YYYY-MM-DD", "2016-10-06T00:00:00+00:00", None), + ("Tuesday", "dddd", "2015-11-10T00:00:00+00:00", None), + ("Monday", "dddd", "2018-01-29T00:00:00+00:00", "2018-02-02"), + ("Mon", "ddd", "2018-01-29T00:00:00+00:00", "2018-02-02"), + ("Mo", "dd", "2018-01-29T00:00:00+00:00", "2018-02-02"), + ("0", "d", "2018-02-04T00:00:00+00:00", "2018-02-02"), + ("1", "E", "2018-01-29T00:00:00+00:00", "2018-02-02"), + ("March", "MMMM", "2018-03-01T00:00:00+00:00", "2018-02-02"), + ("Mar", "MMM", "2018-03-01T00:00:00+00:00", "2018-02-02"), + ( + "Thursday 25th December 1975 02:15:16 PM", + "dddd Do MMMM YYYY hh:mm:ss A", + "1975-12-25T14:15:16+00:00", + None, + ), + ( + "Thursday 25th December 1975 02:15:16 PM -05:00", + "dddd Do MMMM YYYY hh:mm:ss A Z", + "1975-12-25T14:15:16-05:00", + None, + ), + ( + "1975-12-25T14:15:16 America/Guayaquil", + "YYYY-MM-DDTHH:mm:ss z", + "1975-12-25T14:15:16-05:00", + None, + ), + ( + "1975-12-25T14:15:16 America/New_York", + "YYYY-MM-DDTHH:mm:ss z", + "1975-12-25T14:15:16-05:00", + None, + ), + ( + "1975-12-25T14:15:16 Africa/Porto-Novo", + "YYYY-MM-DDTHH:mm:ss z", + "1975-12-25T14:15:16+01:00", + None, + ), + ( + "1975-12-25T14:15:16 Etc/GMT+0", + "YYYY-MM-DDTHH:mm:ss z", + "1975-12-25T14:15:16+00:00", + None, + ), + ( + "1975-12-25T14:15:16 W-SU", + "YYYY-MM-DDTHH:mm:ss z", + "1975-12-25T14:15:16+03:00", + None, + ), + ("190022215", "YYDDDDHHmm", "2019-01-02T22:15:00+00:00", None), + ], +) +def test_from_format(text, fmt, expected, now): + if now is None: + now = pendulum.datetime(2015, 11, 12) + else: + now = pendulum.parse(now) + + with pendulum.travel_to(now, freeze=True): + assert pendulum.from_format(text, fmt).isoformat() == expected + + +@pytest.mark.parametrize( + "text,fmt,expected", + [ + ("lundi", "dddd", "2018-01-29T00:00:00+00:00"), + ("lun.", "ddd", "2018-01-29T00:00:00+00:00"), + ("lu", "dd", "2018-01-29T00:00:00+00:00"), + ("mars", "MMMM", "2018-03-01T00:00:00+00:00"), + ("mars", "MMM", "2018-03-01T00:00:00+00:00"), + ], +) +def test_from_format_with_locale(text, fmt, expected): + now = pendulum.datetime(2018, 2, 2) + + with pendulum.travel_to(now, freeze=True): + formatted = pendulum.from_format(text, fmt, locale="fr").isoformat() + assert formatted == expected + + +@pytest.mark.parametrize( + "text,fmt,locale", + [ + ("23:00", "hh:mm", "en"), + ("23:00 am", "HH:mm a", "en"), + ("invalid", "dddd", "en"), + ("invalid", "ddd", "en"), + ("invalid", "dd", "en"), + ("invalid", "MMMM", "en"), + ("invalid", "MMM", "en"), + ], +) +def test_from_format_error(text, fmt, locale): + now = pendulum.datetime(2018, 2, 2) + + with pendulum.travel_to(now, freeze=True), pytest.raises(ValueError): + pendulum.from_format(text, fmt, locale=locale) + + +def test_strptime(): + d = pendulum.DateTime.strptime("1975-05-21 22:32:11", "%Y-%m-%d %H:%M:%S") + assert_datetime(d, 1975, 5, 21, 22, 32, 11) + assert isinstance(d, pendulum.DateTime) + assert d.timezone_name == "UTC" diff --git a/tests/datetime/test_getters.py b/tests/datetime/test_getters.py new file mode 100644 index 0000000..5074623 --- /dev/null +++ b/tests/datetime/test_getters.py @@ -0,0 +1,248 @@ +from __future__ import annotations + +import struct + +import pytest + +import pendulum + +from pendulum import DateTime +from pendulum.tz import timezone +from tests.conftest import assert_date +from tests.conftest import assert_time + + +def test_year(): + d = pendulum.datetime(1234, 5, 6, 7, 8, 9) + assert d.year == 1234 + + +def test_month(): + d = pendulum.datetime(1234, 5, 6, 7, 8, 9) + assert d.month == 5 + + +def test_day(): + d = pendulum.datetime(1234, 5, 6, 7, 8, 9) + assert d.day == 6 + + +def test_hour(): + d = pendulum.datetime(1234, 5, 6, 7, 8, 9) + assert d.hour == 7 + + +def test_minute(): + d = pendulum.datetime(1234, 5, 6, 7, 8, 9) + assert d.minute == 8 + + +def test_second(): + d = pendulum.datetime(1234, 5, 6, 7, 8, 9) + assert d.second == 9 + + +def test_microsecond(): + d = pendulum.datetime(1234, 5, 6, 7, 8, 9) + assert d.microsecond == 0 + + d = pendulum.datetime(1234, 5, 6, 7, 8, 9, 101112) + assert d.microsecond == 101112 + + +def test_tzinfo(): + d = pendulum.now() + assert d.tzinfo.name == timezone("America/Toronto").name + + +def test_day_of_week(): + d = pendulum.datetime(2012, 5, 7, 7, 8, 9) + assert d.day_of_week == pendulum.MONDAY + + +def test_day_of_year(): + d = pendulum.datetime(2012, 5, 7) + assert d.day_of_year == 128 + + +def test_days_in_month(): + d = pendulum.datetime(2012, 5, 7) + assert d.days_in_month == 31 + + +def test_timestamp(): + d = pendulum.datetime(1970, 1, 1, 0, 0, 0) + assert d.timestamp() == 0 + assert d.add(minutes=1, microseconds=123456).timestamp() == 60.123456 + + +def test_float_timestamp(): + d = pendulum.datetime(1970, 1, 1, 0, 0, 0, 123456) + assert d.float_timestamp == 0.123456 + + +def test_int_timestamp(): + d = pendulum.datetime(1970, 1, 1, 0, 0, 0) + assert d.int_timestamp == 0 + assert d.add(minutes=1, microseconds=123456).int_timestamp == 60 + + +@pytest.mark.skipif( + struct.calcsize("P") * 8 == 32, reason="Test only available for 64bit systems" +) +def test_int_timestamp_accuracy(): + d = pendulum.datetime(3000, 10, 1, 12, 23, 10, 999999) + + assert d.int_timestamp == 32527311790 + + +def test_timestamp_with_transition(): + d_pre = pendulum.datetime(2012, 10, 28, 2, 0, tz="Europe/Warsaw", fold=0) + d_post = pendulum.datetime(2012, 10, 28, 2, 0, tz="Europe/Warsaw", fold=1) + + # the difference between the timestamps before and after is equal to one hour + assert d_post.timestamp() - d_pre.timestamp() == pendulum.SECONDS_PER_HOUR + assert d_post.float_timestamp - d_pre.float_timestamp == (pendulum.SECONDS_PER_HOUR) + assert d_post.int_timestamp - d_pre.int_timestamp == pendulum.SECONDS_PER_HOUR + + +def test_age(): + d = pendulum.now() + assert d.age == 0 + assert d.add(years=1).age == -1 + assert d.subtract(years=1).age == 1 + + +def test_local(): + assert pendulum.datetime(2012, 1, 1, tz="America/Toronto").is_local() + assert pendulum.datetime(2012, 1, 1, tz="America/New_York").is_local() + assert not pendulum.datetime(2012, 1, 1, tz="UTC").is_local() + assert not pendulum.datetime(2012, 1, 1, tz="Europe/London").is_local() + + +def test_utc(): + assert not pendulum.datetime(2012, 1, 1, tz="America/Toronto").is_utc() + assert not pendulum.datetime(2012, 1, 1, tz="Europe/Paris").is_utc() + assert pendulum.datetime(2012, 1, 1, tz="UTC").is_utc() + assert pendulum.datetime(2012, 1, 1, tz=0).is_utc() + assert not pendulum.datetime(2012, 1, 1, tz=5).is_utc() + # There is no time difference between Greenwich Mean Time and Coordinated Universal Time + assert pendulum.datetime(2012, 1, 1, tz="GMT").is_utc() + + +def test_is_dst(): + assert not pendulum.datetime(2012, 1, 1, tz="America/Toronto").is_dst() + assert pendulum.datetime(2012, 7, 1, tz="America/Toronto").is_dst() + + +def test_offset_with_dst(): + assert pendulum.datetime(2012, 1, 1, tz="America/Toronto").offset == -18000 + + +def test_offset_no_dst(): + assert pendulum.datetime(2012, 6, 1, tz="America/Toronto").offset == -14400 + + +def test_offset_for_gmt(): + assert pendulum.datetime(2012, 6, 1, tz="GMT").offset == 0 + + +def test_offset_hours_with_dst(): + assert pendulum.datetime(2012, 1, 1, tz="America/Toronto").offset_hours == -5 + + +def test_offset_hours_no_dst(): + assert pendulum.datetime(2012, 6, 1, tz="America/Toronto").offset_hours == -4 + + +def test_offset_hours_for_gmt(): + assert pendulum.datetime(2012, 6, 1, tz="GMT").offset_hours == 0 + + +def test_offset_hours_float(): + assert pendulum.datetime(2012, 6, 1, tz=9.5).offset_hours == 9.5 + + +def test_is_leap_year(): + assert pendulum.datetime(2012, 1, 1).is_leap_year() + assert not pendulum.datetime(2011, 1, 1).is_leap_year() + + +def test_is_long_year(): + assert pendulum.datetime(2015, 1, 1).is_long_year() + assert not pendulum.datetime(2016, 1, 1).is_long_year() + + +def test_week_of_month(): + assert pendulum.datetime(2012, 9, 30).week_of_month == 5 + assert pendulum.datetime(2012, 9, 28).week_of_month == 5 + assert pendulum.datetime(2012, 9, 20).week_of_month == 4 + assert pendulum.datetime(2012, 9, 8).week_of_month == 2 + assert pendulum.datetime(2012, 9, 1).week_of_month == 1 + assert pendulum.datetime(2020, 1, 1).week_of_month == 1 + assert pendulum.datetime(2020, 1, 7).week_of_month == 2 + assert pendulum.datetime(2020, 1, 14).week_of_month == 3 + + +def test_week_of_year_first_week(): + assert pendulum.datetime(2012, 1, 1).week_of_year == 52 + assert pendulum.datetime(2012, 1, 2).week_of_year == 1 + + +def test_week_of_year_last_week(): + assert pendulum.datetime(2012, 12, 30).week_of_year == 52 + assert pendulum.datetime(2012, 12, 31).week_of_year == 1 + + +def test_timezone(): + d = pendulum.datetime(2000, 1, 1, tz="America/Toronto") + assert d.timezone.name == "America/Toronto" + + d = pendulum.datetime(2000, 1, 1, tz=-5) + assert d.timezone.name == "-05:00" + + +def test_tz(): + d = pendulum.datetime(2000, 1, 1, tz="America/Toronto") + assert d.tz.name == "America/Toronto" + + d = pendulum.datetime(2000, 1, 1, tz=-5) + assert d.tz.name == "-05:00" + + +def test_timezone_name(): + d = pendulum.datetime(2000, 1, 1, tz="America/Toronto") + assert d.timezone_name == "America/Toronto" + + d = pendulum.datetime(2000, 1, 1, tz=-5) + assert d.timezone_name == "-05:00" + + +def test_is_future(): + with pendulum.travel_to(DateTime(2000, 1, 1)): + d = pendulum.now() + assert not d.is_future() + d = d.add(days=1) + assert d.is_future() + + +def test_is_past(): + with pendulum.travel_to(DateTime(2000, 1, 1), freeze=True): + d = pendulum.now() + assert not d.is_past() + d = d.subtract(days=1) + assert d.is_past() + + +def test_date(): + dt = pendulum.datetime(2016, 10, 20, 10, 40, 34, 123456) + d = dt.date() + assert isinstance(d, pendulum.Date) + assert_date(d, 2016, 10, 20) + + +def test_time(): + dt = pendulum.datetime(2016, 10, 20, 10, 40, 34, 123456) + t = dt.time() + assert isinstance(t, pendulum.Time) + assert_time(t, 10, 40, 34, 123456) diff --git a/tests/datetime/test_naive.py b/tests/datetime/test_naive.py new file mode 100644 index 0000000..95bd2d5 --- /dev/null +++ b/tests/datetime/test_naive.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +import pendulum + +from tests.conftest import assert_datetime + + +def test_naive(): + dt = pendulum.naive(2018, 2, 2, 12, 34, 56, 123456) + + assert_datetime(dt, 2018, 2, 2, 12, 34, 56, 123456) + assert dt.tzinfo is None + assert dt.timezone is None + assert dt.timezone_name is None + + +def test_naive_add(): + dt = pendulum.naive(2013, 3, 31, 1, 30) + new = dt.add(hours=1) + + assert_datetime(new, 2013, 3, 31, 2, 30) + + +def test_naive_subtract(): + dt = pendulum.naive(2013, 3, 31, 1, 30) + new = dt.subtract(hours=1) + + assert_datetime(new, 2013, 3, 31, 0, 30) + + +def test_naive_in_timezone(): + dt = pendulum.naive(2013, 3, 31, 1, 30) + new = dt.in_timezone("Europe/Paris") + + assert_datetime(new, 2013, 3, 31, 1, 30) + assert new.timezone_name == "Europe/Paris" + + +def test_naive_in_timezone_dst(): + dt = pendulum.naive(2013, 3, 31, 2, 30) + new = dt.in_timezone("Europe/Paris") + + assert_datetime(new, 2013, 3, 31, 3, 30) + assert new.timezone_name == "Europe/Paris" + + +def test_add(): + dt = pendulum.naive(2013, 3, 31, 2, 30) + new = dt.add(days=3) + + assert_datetime(new, 2013, 4, 3, 2, 30) + + +def test_subtract(): + dt = pendulum.naive(2013, 3, 31, 2, 30) + new = dt.subtract(days=3) + + assert_datetime(new, 2013, 3, 28, 2, 30) + + +def test_to_strings(): + dt = pendulum.naive(2013, 3, 31, 2, 30) + + assert dt.isoformat() == "2013-03-31T02:30:00" + assert dt.to_iso8601_string() == "2013-03-31T02:30:00" + assert dt.to_rfc3339_string() == "2013-03-31T02:30:00" + assert dt.to_atom_string() == "2013-03-31T02:30:00" + assert dt.to_cookie_string() == "Sunday, 31-Mar-2013 02:30:00 " + + +def test_naive_method(): + dt = pendulum.datetime(2018, 2, 2, 12, 34, 56, 123456) + dt = dt.naive() + + assert_datetime(dt, 2018, 2, 2, 12, 34, 56, 123456) + assert dt.tzinfo is None + assert dt.timezone is None + assert dt.timezone_name is None diff --git a/tests/datetime/test_replace.py b/tests/datetime/test_replace.py new file mode 100644 index 0000000..694ef7b --- /dev/null +++ b/tests/datetime/test_replace.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +import pendulum + +from tests.conftest import assert_datetime + + +def test_replace_tzinfo_dst_off(): + utc = pendulum.datetime(2016, 3, 27, 0, 30) # 30 min before DST turning on + in_paris = utc.in_tz("Europe/Paris") + + assert_datetime(in_paris, 2016, 3, 27, 1, 30, 0) + + in_paris = in_paris.replace(second=1) + + assert_datetime(in_paris, 2016, 3, 27, 1, 30, 1) + assert not in_paris.is_dst() + assert in_paris.offset == 3600 + assert in_paris.timezone_name == "Europe/Paris" + + +def test_replace_tzinfo_dst_transitioning_on(): + utc = pendulum.datetime(2016, 3, 27, 1, 30) # In middle of turning on + in_paris = utc.in_tz("Europe/Paris") + + assert_datetime(in_paris, 2016, 3, 27, 3, 30, 0) + + in_paris = in_paris.replace(second=1) + + assert_datetime(in_paris, 2016, 3, 27, 3, 30, 1) + assert in_paris.is_dst() + assert in_paris.offset == 7200 + assert in_paris.timezone_name == "Europe/Paris" + + +def test_replace_tzinfo_dst_on(): + utc = pendulum.datetime(2016, 10, 30, 0, 30) # 30 min before DST turning off + in_paris = utc.in_tz("Europe/Paris") + + assert_datetime(in_paris, 2016, 10, 30, 2, 30, 0) + + in_paris = in_paris.replace(second=1) + + assert_datetime(in_paris, 2016, 10, 30, 2, 30, 1) + assert in_paris.is_dst() + assert in_paris.offset == 7200 + assert in_paris.timezone_name == "Europe/Paris" + + +def test_replace_tzinfo_dst_transitioning_off(): + utc = pendulum.datetime(2016, 10, 30, 1, 30) # In the middle of turning off + in_paris = utc.in_tz("Europe/Paris") + + assert_datetime(in_paris, 2016, 10, 30, 2, 30, 0) + + in_paris = in_paris.replace(second=1) + + assert_datetime(in_paris, 2016, 10, 30, 2, 30, 1) + assert not in_paris.is_dst() + assert in_paris.offset == 3600 + assert in_paris.timezone_name == "Europe/Paris" diff --git a/tests/datetime/test_start_end_of.py b/tests/datetime/test_start_end_of.py new file mode 100644 index 0000000..597dbeb --- /dev/null +++ b/tests/datetime/test_start_end_of.py @@ -0,0 +1,285 @@ +from __future__ import annotations + +import pytest + +import pendulum + +from tests.conftest import assert_datetime + + +def test_start_of_second(): + d = pendulum.now() + new = d.start_of("second") + assert isinstance(new, pendulum.DateTime) + assert_datetime(new, d.year, d.month, d.day, d.hour, d.minute, d.second, 0) + + +def test_end_of_second(): + d = pendulum.now() + new = d.end_of("second") + assert isinstance(new, pendulum.DateTime) + assert_datetime(new, d.year, d.month, d.day, d.hour, d.minute, d.second, 999999) + + +def test_start_of_minute(): + d = pendulum.now() + new = d.start_of("minute") + assert isinstance(new, pendulum.DateTime) + assert_datetime(new, d.year, d.month, d.day, d.hour, d.minute, 0, 0) + + +def test_end_of_minute(): + d = pendulum.now() + new = d.end_of("minute") + assert isinstance(new, pendulum.DateTime) + assert_datetime(new, d.year, d.month, d.day, d.hour, d.minute, 59, 999999) + + +def test_start_of_hour(): + d = pendulum.now() + new = d.start_of("hour") + assert isinstance(new, pendulum.DateTime) + assert_datetime(new, d.year, d.month, d.day, d.hour, 0, 0, 0) + + +def test_end_of_hour(): + d = pendulum.now() + new = d.end_of("hour") + assert isinstance(new, pendulum.DateTime) + assert_datetime(new, d.year, d.month, d.day, d.hour, 59, 59, 999999) + + +def test_start_of_day(): + d = pendulum.now() + new = d.start_of("day") + assert isinstance(new, pendulum.DateTime) + assert_datetime(new, d.year, d.month, d.day, 0, 0, 0, 0) + + +def test_end_of_day(): + d = pendulum.now() + new = d.end_of("day") + assert isinstance(new, pendulum.DateTime) + assert_datetime(new, d.year, d.month, d.day, 23, 59, 59, 999999) + + +def test_start_of_month_is_fluid(): + d = pendulum.now() + assert isinstance(d.start_of("month"), pendulum.DateTime) + + +def test_start_of_month_from_now(): + d = pendulum.now() + new = d.start_of("month") + assert_datetime(new, d.year, d.month, 1, 0, 0, 0, 0) + + +def test_start_of_month_from_last_day(): + d = pendulum.datetime(2000, 1, 31, 2, 3, 4) + new = d.start_of("month") + assert_datetime(new, 2000, 1, 1, 0, 0, 0, 0) + + +def test_start_of_year_is_fluid(): + d = pendulum.now() + new = d.start_of("year") + assert isinstance(new, pendulum.DateTime) + + +def test_start_of_year_from_now(): + d = pendulum.now() + new = d.start_of("year") + assert_datetime(new, d.year, 1, 1, 0, 0, 0, 0) + + +def test_start_of_year_from_first_day(): + d = pendulum.datetime(2000, 1, 1, 1, 1, 1) + new = d.start_of("year") + assert_datetime(new, 2000, 1, 1, 0, 0, 0, 0) + + +def test_start_of_year_from_last_day(): + d = pendulum.datetime(2000, 12, 31, 23, 59, 59) + new = d.start_of("year") + assert_datetime(new, 2000, 1, 1, 0, 0, 0, 0) + + +def test_end_of_month_is_fluid(): + d = pendulum.now() + assert isinstance(d.end_of("month"), pendulum.DateTime) + + +def test_end_of_month(): + d = pendulum.datetime(2000, 1, 1, 2, 3, 4).end_of("month") + new = d.end_of("month") + assert_datetime(new, 2000, 1, 31, 23, 59, 59) + + +def test_end_of_month_from_last_day(): + d = pendulum.datetime(2000, 1, 31, 2, 3, 4) + new = d.end_of("month") + assert_datetime(new, 2000, 1, 31, 23, 59, 59) + + +def test_end_of_year_is_fluid(): + d = pendulum.now() + assert isinstance(d.end_of("year"), pendulum.DateTime) + + +def test_end_of_year_from_now(): + d = pendulum.now().end_of("year") + new = d.end_of("year") + assert_datetime(new, d.year, 12, 31, 23, 59, 59, 999999) + + +def test_end_of_year_from_first_day(): + d = pendulum.datetime(2000, 1, 1, 1, 1, 1) + new = d.end_of("year") + assert_datetime(new, 2000, 12, 31, 23, 59, 59, 999999) + + +def test_end_of_year_from_last_day(): + d = pendulum.datetime(2000, 12, 31, 23, 59, 59, 999999) + new = d.end_of("year") + assert_datetime(new, 2000, 12, 31, 23, 59, 59, 999999) + + +def test_start_of_decade_is_fluid(): + d = pendulum.now() + assert isinstance(d.start_of("decade"), pendulum.DateTime) + + +def test_start_of_decade_from_now(): + d = pendulum.now() + new = d.start_of("decade") + assert_datetime(new, d.year - d.year % 10, 1, 1, 0, 0, 0, 0) + + +def test_start_of_decade_from_first_day(): + d = pendulum.datetime(2000, 1, 1, 1, 1, 1) + new = d.start_of("decade") + assert_datetime(new, 2000, 1, 1, 0, 0, 0, 0) + + +def test_start_of_decade_from_last_day(): + d = pendulum.datetime(2009, 12, 31, 23, 59, 59) + new = d.start_of("decade") + assert_datetime(new, 2000, 1, 1, 0, 0, 0, 0) + + +def test_end_of_decade_is_fluid(): + d = pendulum.now() + assert isinstance(d.end_of("decade"), pendulum.DateTime) + + +def test_end_of_decade_from_now(): + d = pendulum.now() + new = d.end_of("decade") + assert_datetime(new, d.year - d.year % 10 + 9, 12, 31, 23, 59, 59, 999999) + + +def test_end_of_decade_from_first_day(): + d = pendulum.datetime(2000, 1, 1, 1, 1, 1) + new = d.end_of("decade") + assert_datetime(new, 2009, 12, 31, 23, 59, 59, 999999) + + +def test_end_of_decade_from_last_day(): + d = pendulum.datetime(2009, 12, 31, 23, 59, 59, 999999) + new = d.end_of("decade") + assert_datetime(new, 2009, 12, 31, 23, 59, 59, 999999) + + +def test_start_of_century_is_fluid(): + d = pendulum.now() + assert isinstance(d.start_of("century"), pendulum.DateTime) + + +def test_start_of_century_from_now(): + d = pendulum.now() + new = d.start_of("century") + assert_datetime(new, d.year - d.year % 100 + 1, 1, 1, 0, 0, 0, 0) + + +def test_start_of_century_from_first_day(): + d = pendulum.datetime(2001, 1, 1, 1, 1, 1) + new = d.start_of("century") + assert_datetime(new, 2001, 1, 1, 0, 0, 0, 0) + + +def test_start_of_century_from_last_day(): + d = pendulum.datetime(2100, 12, 31, 23, 59, 59) + new = d.start_of("century") + assert_datetime(new, 2001, 1, 1, 0, 0, 0, 0) + + +def test_end_of_century_is_fluid(): + d = pendulum.now() + assert isinstance(d.end_of("century"), pendulum.DateTime) + + +def test_end_of_century_from_now(): + now = pendulum.now() + d = now.end_of("century") + assert_datetime(d, now.year - now.year % 100 + 100, 12, 31, 23, 59, 59, 999999) + + +def test_end_of_century_from_first_day(): + d = pendulum.datetime(2001, 1, 1, 1, 1, 1) + new = d.end_of("century") + assert_datetime(new, 2100, 12, 31, 23, 59, 59, 999999) + + +def test_end_of_century_from_last_day(): + d = pendulum.datetime(2100, 12, 31, 23, 59, 59, 999999) + new = d.end_of("century") + assert_datetime(new, 2100, 12, 31, 23, 59, 59, 999999) + + +def test_average_is_fluid(): + d = pendulum.now().average() + assert isinstance(d, pendulum.DateTime) + + +def test_average_from_same(): + d1 = pendulum.datetime(2000, 1, 31, 2, 3, 4) + d2 = pendulum.datetime(2000, 1, 31, 2, 3, 4).average(d1) + assert_datetime(d2, 2000, 1, 31, 2, 3, 4) + + +def test_average_from_greater(): + d1 = pendulum.datetime(2000, 1, 1, 1, 1, 1, tz="local") + d2 = pendulum.datetime(2009, 12, 31, 23, 59, 59, tz="local").average(d1) + assert_datetime(d2, 2004, 12, 31, 12, 30, 30) + + +def test_average_from_lower(): + d1 = pendulum.datetime(2009, 12, 31, 23, 59, 59, tz="local") + d2 = pendulum.datetime(2000, 1, 1, 1, 1, 1, tz="local").average(d1) + assert_datetime(d2, 2004, 12, 31, 12, 30, 30) + + +def start_of_with_invalid_unit(): + with pytest.raises(ValueError): + pendulum.now().start_of("invalid") + + +def end_of_with_invalid_unit(): + with pytest.raises(ValueError): + pendulum.now().end_of("invalid") + + +def test_start_of_with_transition(): + d = pendulum.datetime(2013, 10, 27, 23, 59, 59, tz="Europe/Paris") + assert d.offset == 3600 + assert d.start_of("month").offset == 7200 + assert d.start_of("day").offset == 7200 + assert d.start_of("year").offset == 3600 + + +def test_end_of_with_transition(): + d = pendulum.datetime(2013, 3, 31, tz="Europe/Paris") + assert d.offset == 3600 + assert d.end_of("month").offset == 7200 + assert d.end_of("day").offset == 7200 + assert d.end_of("year").offset == 3600 diff --git a/tests/datetime/test_strings.py b/tests/datetime/test_strings.py new file mode 100644 index 0000000..0de340d --- /dev/null +++ b/tests/datetime/test_strings.py @@ -0,0 +1,141 @@ +from __future__ import annotations + +import pytest + +import pendulum + + +def test_to_string(): + d = pendulum.datetime(1975, 12, 25, 0, 0, 0, 0, tz="local") + assert str(d) == d.to_iso8601_string() + d = pendulum.datetime(1975, 12, 25, 0, 0, 0, 123456, tz="local") + assert str(d) == d.to_iso8601_string() + + +def test_to_date_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16) + + assert d.to_date_string() == "1975-12-25" + + +def test_to_formatted_date_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16) + + assert d.to_formatted_date_string() == "Dec 25, 1975" + + +def test_to_timestring(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16) + + assert d.to_time_string() == "14:15:16" + + +def test_to_atom_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_atom_string() == "1975-12-25T14:15:16-05:00" + + +def test_to_cookie_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_cookie_string() == "Thursday, 25-Dec-1975 14:15:16 EST" + + +def test_to_iso8601_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_iso8601_string() == "1975-12-25T14:15:16-05:00" + + +def test_to_iso8601_string_utc(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16) + assert d.to_iso8601_string() == "1975-12-25T14:15:16Z" + + +def test_to_iso8601_extended_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, 123456, tz="local") + assert d.to_iso8601_string() == "1975-12-25T14:15:16.123456-05:00" + + +def test_to_rfc822_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_rfc822_string() == "Thu, 25 Dec 75 14:15:16 -0500" + + +def test_to_rfc850_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_rfc850_string() == "Thursday, 25-Dec-75 14:15:16 EST" + + +def test_to_rfc1036_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_rfc1036_string() == "Thu, 25 Dec 75 14:15:16 -0500" + + +def test_to_rfc1123_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_rfc1123_string() == "Thu, 25 Dec 1975 14:15:16 -0500" + + +def test_to_rfc2822_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_rfc2822_string() == "Thu, 25 Dec 1975 14:15:16 -0500" + + +def test_to_rfc3339_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_rfc3339_string() == "1975-12-25T14:15:16-05:00" + + +def test_to_rfc3339_extended_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, 123456, tz="local") + assert d.to_rfc3339_string() == "1975-12-25T14:15:16.123456-05:00" + + +def test_to_rss_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_rss_string() == "Thu, 25 Dec 1975 14:15:16 -0500" + + +def test_to_w3c_string(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.to_w3c_string() == "1975-12-25T14:15:16-05:00" + + +def test_to_string_invalid(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + + with pytest.raises(ValueError): + d._to_string("invalid") + + +def test_repr(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + expected = f"DateTime(1975, 12, 25, 14, 15, 16, tzinfo={repr(d.tzinfo)})" + assert repr(d) == expected + + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, 123456, tz="local") + expected = f"DateTime(1975, 12, 25, 14, 15, 16, 123456, tzinfo={repr(d.tzinfo)})" + assert repr(d) == expected + + +def test_format_with_locale(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + expected = "jeudi 25e jour de décembre 1975 02:15:16 PM -05:00" + assert d.format("dddd Do [jour de] MMMM YYYY hh:mm:ss A Z", locale="fr") == expected + + +def test_strftime(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.strftime("%d") == "25" + + +def test_for_json(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="local") + assert d.for_json() == "1975-12-25T14:15:16-05:00" + + +def test_format(): + d = pendulum.datetime(1975, 12, 25, 14, 15, 16, tz="Europe/Paris") + assert f"{d}" == "1975-12-25T14:15:16+01:00" + assert f"{d:YYYY}" == "1975" + assert f"{d:%Y}" == "1975" + assert f"{d:%H:%M %d.%m.%Y}" == "14:15 25.12.1975" diff --git a/tests/datetime/test_sub.py b/tests/datetime/test_sub.py new file mode 100644 index 0000000..1e51977 --- /dev/null +++ b/tests/datetime/test_sub.py @@ -0,0 +1,251 @@ +from __future__ import annotations + +from datetime import timedelta + +import pytest + +import pendulum + +from tests.conftest import assert_datetime + + +def test_sub_years_positive(): + assert pendulum.datetime(1975, 1, 1).subtract(years=1).year == 1974 + + +def test_sub_years_zero(): + assert pendulum.datetime(1975, 1, 1).subtract(years=0).year == 1975 + + +def test_sub_years_negative(): + assert pendulum.datetime(1975, 1, 1).subtract(years=-1).year == 1976 + + +def test_sub_months_positive(): + assert pendulum.datetime(1975, 12, 1).subtract(months=1).month == 11 + + +def test_sub_months_zero(): + assert pendulum.datetime(1975, 12, 1).subtract(months=0).month == 12 + + +def test_sub_months_negative(): + assert pendulum.datetime(1975, 12, 1).subtract(months=-1).month == 1 + + +def test_sub_days_positive(): + assert pendulum.datetime(1975, 5, 31).subtract(days=1).day == 30 + + +def test_sub_days_zero(): + assert pendulum.datetime(1975, 5, 31).subtract(days=0).day == 31 + + +def test_sub_days_negative(): + assert pendulum.datetime(1975, 5, 31).subtract(days=-1).day == 1 + + +def test_sub_weeks_positive(): + assert pendulum.datetime(1975, 5, 21).subtract(weeks=1).day == 14 + + +def test_sub_weeks_zero(): + assert pendulum.datetime(1975, 5, 21).subtract(weeks=0).day == 21 + + +def test_sub_weeks_negative(): + assert pendulum.datetime(1975, 5, 21).subtract(weeks=-1).day == 28 + + +def test_sub_hours_positive(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).subtract(hours=1).hour == 23 + + +def test_sub_hours_zero(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).subtract(hours=0).hour == 0 + + +def test_sub_hours_negative(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).subtract(hours=-1).hour == 1 + + +def test_sub_minutes_positive(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).subtract(minutes=1).minute == 59 + + +def test_sub_minutes_zero(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).subtract(minutes=0).minute == 0 + + +def test_sub_minutes_negative(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).subtract(minutes=-1).minute == 1 + + +def test_sub_seconds_positive(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).subtract(seconds=1).second == 59 + + +def test_sub_seconds_zero(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).subtract(seconds=0).second == 0 + + +def test_sub_seconds_negative(): + assert pendulum.datetime(1975, 5, 21, 0, 0, 0).subtract(seconds=-1).second == 1 + + +def test_subtract_timedelta(): + delta = timedelta(days=6, seconds=16, microseconds=654321) + d = pendulum.datetime(2015, 3, 14, 3, 12, 15, 777777) + + d = d - delta + assert d.day == 8 + assert d.minute == 11 + assert d.second == 59 + assert d.microsecond == 123456 + + +def test_subtract_duration(): + duration = pendulum.duration( + years=2, months=3, days=6, seconds=16, microseconds=654321 + ) + d = pendulum.datetime(2015, 3, 14, 3, 12, 15, 777777) + + d = d - duration + assert d.year == 2012 + assert d.month == 12 + assert d.day == 8 + assert d.hour == 3 + assert d.minute == 11 + assert d.second == 59 + assert d.microsecond == 123456 + + +def test_subtract_time_to_new_transition_skipped(): + dt = pendulum.datetime(2013, 3, 31, 3, 0, 0, 0, tz="Europe/Paris") + + assert_datetime(dt, 2013, 3, 31, 3, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 7200 + assert dt.is_dst() + + dt = dt.subtract(microseconds=1) + + assert_datetime(dt, 2013, 3, 31, 1, 59, 59, 999999) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 3600 + assert not dt.is_dst() + + dt = pendulum.datetime(2013, 3, 10, 3, 0, 0, 0, tz="America/New_York") + + assert_datetime(dt, 2013, 3, 10, 3, 0, 0, 0) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -4 * 3600 + assert dt.is_dst() + + dt = dt.subtract(microseconds=1) + + assert_datetime(dt, 2013, 3, 10, 1, 59, 59, 999999) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -5 * 3600 + assert not dt.is_dst() + + dt = pendulum.datetime(1957, 4, 28, 3, 0, 0, 0, tz="America/New_York") + + assert_datetime(dt, 1957, 4, 28, 3, 0, 0, 0) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -4 * 3600 + assert dt.is_dst() + + dt = dt.subtract(microseconds=1) + + assert_datetime(dt, 1957, 4, 28, 1, 59, 59, 999999) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -5 * 3600 + assert not dt.is_dst() + + +def test_subtract_time_to_new_transition_skipped_big(): + dt = pendulum.datetime(2013, 3, 31, 3, 0, 0, 0, tz="Europe/Paris") + + assert_datetime(dt, 2013, 3, 31, 3, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 7200 + assert dt.is_dst() + + dt = dt.subtract(days=1) + + assert_datetime(dt, 2013, 3, 30, 3, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 3600 + assert not dt.is_dst() + + +def test_subtract_time_to_new_transition_repeated(): + dt = pendulum.datetime(2013, 10, 27, 2, 0, 0, 0, tz="Europe/Paris") + + assert_datetime(dt, 2013, 10, 27, 2, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 3600 + assert not dt.is_dst() + + dt = dt.subtract(microseconds=1) + + assert_datetime(dt, 2013, 10, 27, 2, 59, 59, 999999) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 7200 + assert dt.is_dst() + + dt = pendulum.datetime(2013, 11, 3, 1, 0, 0, 0, tz="America/New_York") + + assert_datetime(dt, 2013, 11, 3, 1, 0, 0, 0) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -5 * 3600 + assert not dt.is_dst() + + dt = dt.subtract(microseconds=1) + + assert_datetime(dt, 2013, 11, 3, 1, 59, 59, 999999) + assert dt.timezone_name == "America/New_York" + assert dt.offset == -4 * 3600 + assert dt.is_dst() + + +def test_subtract_time_to_new_transition_repeated_big(): + dt = pendulum.datetime(2013, 10, 27, 2, 0, 0, 0, tz="Europe/Paris") + + assert_datetime(dt, 2013, 10, 27, 2, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 3600 + assert not dt.is_dst() + + dt = dt.subtract(days=1) + + assert_datetime(dt, 2013, 10, 26, 2, 0, 0, 0) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 7200 + assert dt.is_dst() + + +def test_subtract_invalid_type(): + d = pendulum.datetime(1975, 5, 21, 0, 0, 0) + + with pytest.raises(TypeError): + d - "ab" + + with pytest.raises(TypeError): + "ab" - d + + +def test_subtract_negative_over_dls_transitioning_off(): + just_before_dls_ends = pendulum.datetime( + 2019, 11, 3, 1, 30, tz="US/Pacific", fold=0 + ) + plus_10_hours = just_before_dls_ends + timedelta(hours=10) + minus_neg_10_hours = just_before_dls_ends - timedelta(hours=-10) + + # 1:30-0700 becomes 10:30-0800 + assert plus_10_hours.hour == 10 + assert minus_neg_10_hours.hour == 10 + assert just_before_dls_ends.is_dst() + assert not plus_10_hours.is_dst() + assert not minus_neg_10_hours.is_dst() diff --git a/tests/datetime/test_timezone.py b/tests/datetime/test_timezone.py new file mode 100644 index 0000000..343435d --- /dev/null +++ b/tests/datetime/test_timezone.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +import pendulum + +from tests.conftest import assert_datetime + + +def test_in_timezone(): + d = pendulum.datetime(2015, 1, 15, 18, 15, 34) + now = pendulum.datetime(2015, 1, 15, 18, 15, 34) + assert d.timezone_name == "UTC" + assert_datetime(d, now.year, now.month, now.day, now.hour, now.minute) + + d = d.in_timezone("Europe/Paris") + assert d.timezone_name == "Europe/Paris" + assert_datetime(d, now.year, now.month, now.day, now.hour + 1, now.minute) + + +def test_in_tz(): + d = pendulum.datetime(2015, 1, 15, 18, 15, 34) + now = pendulum.datetime(2015, 1, 15, 18, 15, 34) + assert d.timezone_name == "UTC" + assert_datetime(d, now.year, now.month, now.day, now.hour, now.minute) + + d = d.in_tz("Europe/Paris") + assert d.timezone_name == "Europe/Paris" + assert_datetime(d, now.year, now.month, now.day, now.hour + 1, now.minute) + + +def test_astimezone(): + d = pendulum.datetime(2015, 1, 15, 18, 15, 34) + now = pendulum.datetime(2015, 1, 15, 18, 15, 34) + assert d.timezone_name == "UTC" + assert_datetime(d, now.year, now.month, now.day, now.hour, now.minute) + + d = d.astimezone(pendulum.timezone("Europe/Paris")) + assert d.timezone_name == "Europe/Paris" + assert_datetime(d, now.year, now.month, now.day, now.hour + 1, now.minute) |