From d6d80a17444c90259c5bfdacb84c61e6bfece655 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 5 Jan 2023 11:38:41 +0100 Subject: Merging upstream version 3.0.0~a1. Signed-off-by: Daniel Baumann --- tests/__init__.py | 0 tests/conftest.py | 101 +++ tests/date/__init__.py | 0 tests/date/test_add.py | 88 +++ tests/date/test_behavior.py | 73 ++ tests/date/test_comparison.py | 247 ++++++ tests/date/test_construct.py | 16 + tests/date/test_day_of_week_modifiers.py | 298 +++++++ tests/date/test_diff.py | 365 +++++++++ tests/date/test_fluent_setters.py | 29 + tests/date/test_getters.py | 87 ++ tests/date/test_start_end_of.py | 252 ++++++ tests/date/test_strings.py | 48 ++ tests/date/test_sub.py | 90 +++ tests/datetime/__init__.py | 0 tests/datetime/test_add.py | 268 +++++++ tests/datetime/test_behavior.py | 172 ++++ tests/datetime/test_comparison.py | 394 +++++++++ tests/datetime/test_construct.py | 182 +++++ tests/datetime/test_create_from_timestamp.py | 24 + tests/datetime/test_day_of_week_modifiers.py | 314 ++++++++ tests/datetime/test_diff.py | 880 +++++++++++++++++++++ tests/datetime/test_fluent_setters.py | 181 +++++ tests/datetime/test_from_format.py | 203 +++++ tests/datetime/test_getters.py | 248 ++++++ tests/datetime/test_naive.py | 78 ++ tests/datetime/test_replace.py | 61 ++ tests/datetime/test_start_end_of.py | 285 +++++++ tests/datetime/test_strings.py | 141 ++++ tests/datetime/test_sub.py | 251 ++++++ tests/datetime/test_timezone.py | 38 + tests/duration/__init__.py | 0 tests/duration/test_add_sub.py | 54 ++ tests/duration/test_arithmetic.py | 85 ++ tests/duration/test_behavior.py | 21 + tests/duration/test_construct.py | 99 +++ tests/duration/test_in_methods.py | 28 + tests/duration/test_in_words.py | 77 ++ tests/duration/test_total_methods.py | 28 + tests/fixtures/__init__.py | 0 tests/fixtures/tz/Paris | Bin 0 -> 2971 bytes tests/fixtures/tz/clock/etc/sysconfig/clock | 1 + tests/fixtures/tz/symlink/etc/localtime | 1 + .../tz/symlink/usr/share/zoneinfo/Europe/Paris | Bin 0 -> 2971 bytes tests/fixtures/tz/timezone_dir/etc/localtime | 1 + .../fixtures/tz/timezone_dir/etc/timezone/blank.md | 5 + .../timezone_dir/usr/share/zoneinfo/Europe/Paris | Bin 0 -> 2971 bytes tests/formatting/__init__.py | 0 tests/formatting/test_formatter.py | 263 ++++++ tests/helpers/__init__.py | 0 tests/helpers/test_local_time.py | 31 + tests/interval/__init__.py | 0 tests/interval/test_add_subtract.py | 49 ++ tests/interval/test_arithmetic.py | 53 ++ tests/interval/test_behavior.py | 54 ++ tests/interval/test_construct.py | 121 +++ tests/interval/test_hashing.py | 23 + tests/interval/test_in_words.py | 70 ++ tests/interval/test_range.py | 119 +++ tests/localization/__init__.py | 0 tests/localization/test_cs.py | 109 +++ tests/localization/test_da.py | 65 ++ tests/localization/test_de.py | 65 ++ tests/localization/test_es.py | 65 ++ tests/localization/test_fa.py | 65 ++ tests/localization/test_fo.py | 65 ++ tests/localization/test_fr.py | 84 ++ tests/localization/test_he.py | 65 ++ tests/localization/test_id.py | 68 ++ tests/localization/test_it.py | 85 ++ tests/localization/test_ja.py | 68 ++ tests/localization/test_ko.py | 65 ++ tests/localization/test_lt.py | 68 ++ tests/localization/test_nb.py | 84 ++ tests/localization/test_nl.py | 83 ++ tests/localization/test_nn.py | 84 ++ tests/localization/test_pl.py | 109 +++ tests/localization/test_ru.py | 86 ++ tests/localization/test_sk.py | 112 +++ tests/localization/test_sv.py | 86 ++ tests/parsing/__init__.py | 0 tests/parsing/test_parse_iso8601.py | 465 +++++++++++ tests/parsing/test_parsing.py | 687 ++++++++++++++++ tests/parsing/test_parsing_duration.py | 298 +++++++ tests/test_helpers.py | 179 +++++ tests/test_main.py | 13 + tests/test_parsing.py | 141 ++++ tests/testing/__init__.py | 0 tests/testing/test_time_travel.py | 85 ++ tests/time/__init__.py | 0 tests/time/test_add.py | 78 ++ tests/time/test_behavior.py | 49 ++ tests/time/test_comparison.py | 185 +++++ tests/time/test_construct.py | 22 + tests/time/test_diff.py | 350 ++++++++ tests/time/test_fluent_setters.py | 12 + tests/time/test_strings.py | 39 + tests/time/test_sub.py | 112 +++ tests/tz/__init__.py | 0 tests/tz/test_helpers.py | 27 + tests/tz/test_local_timezone.py | 52 ++ tests/tz/test_timezone.py | 447 +++++++++++ tests/tz/test_timezones.py | 16 + 103 files changed, 11435 insertions(+) create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/date/__init__.py create mode 100644 tests/date/test_add.py create mode 100644 tests/date/test_behavior.py create mode 100644 tests/date/test_comparison.py create mode 100644 tests/date/test_construct.py create mode 100644 tests/date/test_day_of_week_modifiers.py create mode 100644 tests/date/test_diff.py create mode 100644 tests/date/test_fluent_setters.py create mode 100644 tests/date/test_getters.py create mode 100644 tests/date/test_start_end_of.py create mode 100644 tests/date/test_strings.py create mode 100644 tests/date/test_sub.py create mode 100644 tests/datetime/__init__.py create mode 100644 tests/datetime/test_add.py create mode 100644 tests/datetime/test_behavior.py create mode 100644 tests/datetime/test_comparison.py create mode 100644 tests/datetime/test_construct.py create mode 100644 tests/datetime/test_create_from_timestamp.py create mode 100644 tests/datetime/test_day_of_week_modifiers.py create mode 100644 tests/datetime/test_diff.py create mode 100644 tests/datetime/test_fluent_setters.py create mode 100644 tests/datetime/test_from_format.py create mode 100644 tests/datetime/test_getters.py create mode 100644 tests/datetime/test_naive.py create mode 100644 tests/datetime/test_replace.py create mode 100644 tests/datetime/test_start_end_of.py create mode 100644 tests/datetime/test_strings.py create mode 100644 tests/datetime/test_sub.py create mode 100644 tests/datetime/test_timezone.py create mode 100644 tests/duration/__init__.py create mode 100644 tests/duration/test_add_sub.py create mode 100644 tests/duration/test_arithmetic.py create mode 100644 tests/duration/test_behavior.py create mode 100644 tests/duration/test_construct.py create mode 100644 tests/duration/test_in_methods.py create mode 100644 tests/duration/test_in_words.py create mode 100644 tests/duration/test_total_methods.py create mode 100644 tests/fixtures/__init__.py create mode 100644 tests/fixtures/tz/Paris create mode 100644 tests/fixtures/tz/clock/etc/sysconfig/clock create mode 120000 tests/fixtures/tz/symlink/etc/localtime create mode 100644 tests/fixtures/tz/symlink/usr/share/zoneinfo/Europe/Paris create mode 120000 tests/fixtures/tz/timezone_dir/etc/localtime create mode 100644 tests/fixtures/tz/timezone_dir/etc/timezone/blank.md create mode 100644 tests/fixtures/tz/timezone_dir/usr/share/zoneinfo/Europe/Paris create mode 100644 tests/formatting/__init__.py create mode 100644 tests/formatting/test_formatter.py create mode 100644 tests/helpers/__init__.py create mode 100644 tests/helpers/test_local_time.py create mode 100644 tests/interval/__init__.py create mode 100644 tests/interval/test_add_subtract.py create mode 100644 tests/interval/test_arithmetic.py create mode 100644 tests/interval/test_behavior.py create mode 100644 tests/interval/test_construct.py create mode 100644 tests/interval/test_hashing.py create mode 100644 tests/interval/test_in_words.py create mode 100644 tests/interval/test_range.py create mode 100644 tests/localization/__init__.py create mode 100644 tests/localization/test_cs.py create mode 100644 tests/localization/test_da.py create mode 100644 tests/localization/test_de.py create mode 100644 tests/localization/test_es.py create mode 100644 tests/localization/test_fa.py create mode 100644 tests/localization/test_fo.py create mode 100644 tests/localization/test_fr.py create mode 100644 tests/localization/test_he.py create mode 100644 tests/localization/test_id.py create mode 100644 tests/localization/test_it.py create mode 100644 tests/localization/test_ja.py create mode 100644 tests/localization/test_ko.py create mode 100644 tests/localization/test_lt.py create mode 100644 tests/localization/test_nb.py create mode 100644 tests/localization/test_nl.py create mode 100644 tests/localization/test_nn.py create mode 100644 tests/localization/test_pl.py create mode 100644 tests/localization/test_ru.py create mode 100644 tests/localization/test_sk.py create mode 100644 tests/localization/test_sv.py create mode 100644 tests/parsing/__init__.py create mode 100644 tests/parsing/test_parse_iso8601.py create mode 100644 tests/parsing/test_parsing.py create mode 100644 tests/parsing/test_parsing_duration.py create mode 100644 tests/test_helpers.py create mode 100644 tests/test_main.py create mode 100644 tests/test_parsing.py create mode 100644 tests/testing/__init__.py create mode 100644 tests/testing/test_time_travel.py create mode 100644 tests/time/__init__.py create mode 100644 tests/time/test_add.py create mode 100644 tests/time/test_behavior.py create mode 100644 tests/time/test_comparison.py create mode 100644 tests/time/test_construct.py create mode 100644 tests/time/test_diff.py create mode 100644 tests/time/test_fluent_setters.py create mode 100644 tests/time/test_strings.py create mode 100644 tests/time/test_sub.py create mode 100644 tests/tz/__init__.py create mode 100644 tests/tz/test_helpers.py create mode 100644 tests/tz/test_local_timezone.py create mode 100644 tests/tz/test_timezone.py create mode 100644 tests/tz/test_timezones.py (limited to 'tests') diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..060e951 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +import pytest + +import pendulum + + +@pytest.fixture(autouse=True) +def setup(): + pendulum.set_local_timezone(pendulum.timezone("America/Toronto")) + + yield + + pendulum.set_locale("en") + pendulum.set_local_timezone() + pendulum.week_starts_at(pendulum.MONDAY) + pendulum.week_ends_at(pendulum.SUNDAY) + + +def assert_datetime( + d, year, month, day, hour=None, minute=None, second=None, microsecond=None +): + assert year == d.year + assert month == d.month + assert day == d.day + + if hour is not None: + assert hour == d.hour + + if minute is not None: + assert minute == d.minute + + if second is not None: + assert second == d.second + + if microsecond is not None: + assert microsecond == d.microsecond + + +def assert_date(d, year, month, day): + assert year == d.year + assert month == d.month + assert day == d.day + + +def assert_time(t, hour, minute, second, microsecond=None): + assert hour == t.hour + assert minute == t.minute + assert second == t.second + + if microsecond is not None: + assert microsecond == t.microsecond + + +def assert_duration( + dur, + years=None, + months=None, + weeks=None, + days=None, + hours=None, + minutes=None, + seconds=None, + microseconds=None, +) -> None: + expected = {} + actual = {} + + if years is not None: + expected["years"] = dur.years + actual["years"] = years + + if months is not None: + expected["months"] = dur.months + actual["months"] = months + + if weeks is not None: + expected["weeks"] = dur.weeks + actual["weeks"] = weeks + + if days is not None: + expected["days"] = dur.remaining_days + actual["days"] = days + + if hours is not None: + expected["hours"] = dur.hours + actual["hours"] = hours + + if minutes is not None: + expected["minutes"] = dur.minutes + actual["minutes"] = minutes + + if seconds is not None: + expected["seconds"] = dur.remaining_seconds + actual["seconds"] = seconds + + if microseconds is not None: + expected["microseconds"] = dur.microseconds + actual["microseconds"] = microseconds + + assert expected == actual diff --git a/tests/date/__init__.py b/tests/date/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/date/test_add.py b/tests/date/test_add.py new file mode 100644 index 0000000..a435f46 --- /dev/null +++ b/tests/date/test_add.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from datetime import timedelta + +import pytest + +import pendulum + +from tests.conftest import assert_date + + +def test_add_years_positive(): + assert pendulum.date(1975, 1, 1).add(years=1).year == 1976 + + +def test_add_years_zero(): + assert pendulum.date(1975, 1, 1).add(years=0).year == 1975 + + +def test_add_years_negative(): + assert pendulum.date(1975, 1, 1).add(years=-1).year == 1974 + + +def test_add_months_positive(): + assert pendulum.date(1975, 12, 1).add(months=1).month == 1 + + +def test_add_months_zero(): + assert pendulum.date(1975, 12, 1).add(months=0).month == 12 + + +def test_add_months_negative(): + assert pendulum.date(1975, 12, 1).add(months=-1).month == 11 + + +def test_add_month_with_overflow(): + assert pendulum.Date(2012, 1, 31).add(months=1).month == 2 + + +def test_add_days_positive(): + assert pendulum.Date(1975, 5, 31).add(days=1).day == 1 + + +def test_add_days_zero(): + assert pendulum.Date(1975, 5, 31).add(days=0).day == 31 + + +def test_add_days_negative(): + assert pendulum.Date(1975, 5, 31).add(days=-1).day == 30 + + +def test_add_weeks_positive(): + assert pendulum.Date(1975, 5, 21).add(weeks=1).day == 28 + + +def test_add_weeks_zero(): + assert pendulum.Date(1975, 5, 21).add(weeks=0).day == 21 + + +def test_add_weeks_negative(): + assert pendulum.Date(1975, 5, 21).add(weeks=-1).day == 14 + + +def test_add_timedelta(): + delta = timedelta(days=18) + d = pendulum.date(2015, 3, 14) + + new = d + delta + assert isinstance(new, pendulum.Date) + assert_date(new, 2015, 4, 1) + + +def test_add_duration(): + duration = pendulum.duration(years=2, months=3, days=18) + d = pendulum.Date(2015, 3, 14) + + new = d + duration + assert_date(new, 2017, 7, 2) + + +def test_addition_invalid_type(): + d = pendulum.date(2015, 3, 14) + + with pytest.raises(TypeError): + d + 3 + + with pytest.raises(TypeError): + 3 + d diff --git a/tests/date/test_behavior.py b/tests/date/test_behavior.py new file mode 100644 index 0000000..98dd175 --- /dev/null +++ b/tests/date/test_behavior.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +import pickle + +from datetime import date + +import pytest + +import pendulum + + +@pytest.fixture() +def p(): + return pendulum.Date(2016, 8, 27) + + +@pytest.fixture() +def d(): + return date(2016, 8, 27) + + +def test_timetuple(p, d): + assert p.timetuple() == d.timetuple() + + +def test_ctime(p, d): + assert p.ctime() == d.ctime() + + +def test_isoformat(p, d): + assert p.isoformat() == d.isoformat() + + +def test_toordinal(p, d): + assert p.toordinal() == d.toordinal() + + +def test_weekday(p, d): + assert p.weekday() == d.weekday() + + +def test_isoweekday(p, d): + assert p.isoweekday() == d.isoweekday() + + +def test_isocalendar(p, d): + assert p.isocalendar() == d.isocalendar() + + +def test_fromtimestamp(): + assert pendulum.Date.fromtimestamp(0) == date.fromtimestamp(0) + + +def test_fromordinal(): + assert pendulum.Date.fromordinal(730120) == date.fromordinal(730120) + + +def test_hash(): + d1 = pendulum.Date(2016, 8, 27) + d2 = pendulum.Date(2016, 8, 27) + d3 = pendulum.Date(2016, 8, 28) + + assert hash(d2) == hash(d1) + assert hash(d1) != hash(d3) + + +def test_pickle(): + d1 = pendulum.Date(2016, 8, 27) + s = pickle.dumps(d1) + d2 = pickle.loads(s) + + assert isinstance(d2, pendulum.Date) + assert d2 == d1 diff --git a/tests/date/test_comparison.py b/tests/date/test_comparison.py new file mode 100644 index 0000000..94bf224 --- /dev/null +++ b/tests/date/test_comparison.py @@ -0,0 +1,247 @@ +from __future__ import annotations + +from datetime import date + +import pendulum + +from tests.conftest import assert_date + + +def test_equal_to_true(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 1) + d3 = date(2000, 1, 1) + + assert d2 == d1 + assert d3 == d1 + + +def test_equal_to_false(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 2) + d3 = date(2000, 1, 2) + + assert d1 != d2 + assert d1 != d3 + + +def test_not_equal_to_true(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 2) + d3 = date(2000, 1, 2) + + assert d1 != d2 + assert d1 != d3 + + +def test_not_equal_to_false(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 1) + d3 = date(2000, 1, 1) + + assert d2 == d1 + assert d3 == d1 + + +def test_not_equal_to_none(): + d1 = pendulum.Date(2000, 1, 1) + + assert d1 != None # noqa + + +def test_greater_than_true(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(1999, 12, 31) + d3 = date(1999, 12, 31) + + assert d1 > d2 + assert d1 > d3 + + +def test_greater_than_false(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 2) + d3 = date(2000, 1, 2) + + assert not d1 > d2 + assert not d1 > d3 + + +def test_greater_than_or_equal_true(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(1999, 12, 31) + d3 = date(1999, 12, 31) + + assert d1 >= d2 + assert d1 >= d3 + + +def test_greater_than_or_equal_true_equal(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 1) + d3 = date(2000, 1, 1) + + assert d1 >= d2 + assert d1 >= d3 + + +def test_greater_than_or_equal_false(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 2) + d3 = date(2000, 1, 2) + + assert not d1 >= d2 + assert not d1 >= d3 + + +def test_less_than_true(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 2) + d3 = date(2000, 1, 2) + + assert d1 < d2 + assert d1 < d3 + + +def test_less_than_false(): + d1 = pendulum.Date(2000, 1, 2) + d2 = pendulum.Date(2000, 1, 1) + d3 = date(2000, 1, 1) + + assert not d1 < d2 + assert not d1 < d3 + + +def test_less_than_or_equal_true(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 2) + d3 = date(2000, 1, 2) + + assert d1 <= d2 + assert d1 <= d3 + + +def test_less_than_or_equal_true_equal(): + d1 = pendulum.Date(2000, 1, 1) + d2 = pendulum.Date(2000, 1, 1) + d3 = date(2000, 1, 1) + + assert d1 <= d2 + assert d1 <= d3 + + +def test_less_than_or_equal_false(): + d1 = pendulum.Date(2000, 1, 2) + d2 = pendulum.Date(2000, 1, 1) + d3 = date(2000, 1, 1) + + assert not d1 <= d2 + assert not d1 <= d3 + + +def test_is_anniversary(): + d = pendulum.Date.today() + 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.Date(1987, 4, 23) + d2 = pendulum.Date(2014, 9, 26) + d3 = pendulum.Date(2014, 4, 23) + assert not d2.is_anniversary(d1) + assert d3.is_anniversary(d1) + + +def test_is_birthday(): # backward compatibility + d = pendulum.Date.today() + 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.Date(1987, 4, 23) + d2 = pendulum.Date(2014, 9, 26) + d3 = pendulum.Date(2014, 4, 23) + assert not d2.is_birthday(d1) + assert d3.is_birthday(d1) + + +def test_closest(): + instance = pendulum.Date(2015, 5, 28) + dt1 = pendulum.Date(2015, 5, 27) + dt2 = pendulum.Date(2015, 5, 30) + closest = instance.closest(dt1, dt2) + assert closest == dt1 + + closest = instance.closest(dt2, dt1) + assert closest == dt1 + + +def test_closest_with_date(): + instance = pendulum.Date(2015, 5, 28) + dt1 = date(2015, 5, 27) + dt2 = date(2015, 5, 30) + closest = instance.closest(dt1, dt2) + assert isinstance(closest, pendulum.Date) + assert_date(closest, 2015, 5, 27) + + +def test_closest_with_equals(): + instance = pendulum.Date(2015, 5, 28) + dt1 = pendulum.Date(2015, 5, 28) + dt2 = pendulum.Date(2015, 5, 30) + closest = instance.closest(dt1, dt2) + assert closest == dt1 + + +def test_farthest(): + instance = pendulum.Date(2015, 5, 28) + dt1 = pendulum.Date(2015, 5, 27) + dt2 = pendulum.Date(2015, 5, 30) + closest = instance.farthest(dt1, dt2) + assert closest == dt2 + + closest = instance.farthest(dt2, dt1) + assert closest == dt2 + + +def test_farthest_with_date(): + instance = pendulum.Date(2015, 5, 28) + dt1 = date(2015, 5, 27) + dt2 = date(2015, 5, 30) + closest = instance.farthest(dt1, dt2) + assert isinstance(closest, pendulum.Date) + assert_date(closest, 2015, 5, 30) + + +def test_farthest_with_equals(): + instance = pendulum.Date(2015, 5, 28) + dt1 = pendulum.Date(2015, 5, 28) + dt2 = pendulum.Date(2015, 5, 30) + closest = instance.farthest(dt1, dt2) + assert closest == dt2 + + +def test_is_same_day(): + dt1 = pendulum.Date(2015, 5, 28) + dt2 = pendulum.Date(2015, 5, 29) + dt3 = pendulum.Date(2015, 5, 28) + dt4 = date(2015, 5, 28) + dt5 = date(2015, 5, 29) + + 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.Date.today() + + assert dt1 != "test" + assert dt1 not in ["test"] diff --git a/tests/date/test_construct.py b/tests/date/test_construct.py new file mode 100644 index 0000000..5b6eb78 --- /dev/null +++ b/tests/date/test_construct.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from pendulum import Date +from tests.conftest import assert_date + + +def test_construct(): + d = Date(2016, 10, 20) + + assert_date(d, 2016, 10, 20) + + +def test_today(): + d = Date.today() + + assert isinstance(d, Date) diff --git a/tests/date/test_day_of_week_modifiers.py b/tests/date/test_day_of_week_modifiers.py new file mode 100644 index 0000000..55aba55 --- /dev/null +++ b/tests/date/test_day_of_week_modifiers.py @@ -0,0 +1,298 @@ +from __future__ import annotations + +import pytest + +import pendulum + +from pendulum.exceptions import PendulumException +from tests.conftest import assert_date + + +def test_start_of_week(): + d = pendulum.date(1980, 8, 7).start_of("week") + assert_date(d, 1980, 8, 4) + + +def test_start_of_week_from_week_start(): + d = pendulum.date(1980, 8, 4).start_of("week") + assert_date(d, 1980, 8, 4) + + +def test_start_of_week_crossing_year_boundary(): + d = pendulum.date(2014, 1, 1).start_of("week") + assert_date(d, 2013, 12, 30) + + +def test_end_of_week(): + d = pendulum.date(1980, 8, 7).end_of("week") + assert_date(d, 1980, 8, 10) + + +def test_end_of_week_from_week_end(): + d = pendulum.date(1980, 8, 10).end_of("week") + assert_date(d, 1980, 8, 10) + + +def test_end_of_week_crossing_year_boundary(): + d = pendulum.date(2013, 12, 31).end_of("week") + assert_date(d, 2014, 1, 5) + + +def test_next(): + d = pendulum.date(1975, 5, 21).next() + assert_date(d, 1975, 5, 28) + + +def test_next_monday(): + d = pendulum.date(1975, 5, 21).next(pendulum.MONDAY) + assert_date(d, 1975, 5, 26) + + +def test_next_saturday(): + d = pendulum.date(1975, 5, 21).next(6) + assert_date(d, 1975, 5, 24) + + +def test_next_invalid(): + dt = pendulum.date(1975, 5, 21) + + with pytest.raises(ValueError): + dt.next(7) + + +def test_previous(): + d = pendulum.date(1975, 5, 21).previous() + assert_date(d, 1975, 5, 14) + + +def test_previous_monday(): + d = pendulum.date(1975, 5, 21).previous(pendulum.MONDAY) + assert_date(d, 1975, 5, 19) + + +def test_previous_saturday(): + d = pendulum.date(1975, 5, 21).previous(6) + assert_date(d, 1975, 5, 17) + + +def test_previous_invalid(): + dt = pendulum.date(1975, 5, 21) + + with pytest.raises(ValueError): + dt.previous(7) + + +def test_first_day_of_month(): + d = pendulum.date(1975, 11, 21).first_of("month") + assert_date(d, 1975, 11, 1) + + +def test_first_wednesday_of_month(): + d = pendulum.date(1975, 11, 21).first_of("month", pendulum.WEDNESDAY) + assert_date(d, 1975, 11, 5) + + +def test_first_friday_of_month(): + d = pendulum.date(1975, 11, 21).first_of("month", 5) + assert_date(d, 1975, 11, 7) + + +def test_last_day_of_month(): + d = pendulum.date(1975, 12, 5).last_of("month") + assert_date(d, 1975, 12, 31) + + +def test_last_tuesday_of_month(): + d = pendulum.date(1975, 12, 1).last_of("month", pendulum.TUESDAY) + assert_date(d, 1975, 12, 30) + + +def test_last_friday_of_month(): + d = pendulum.date(1975, 12, 5).last_of("month", 5) + assert_date(d, 1975, 12, 26) + + +def test_nth_of_month_outside_scope(): + d = pendulum.date(1975, 6, 5) + + with pytest.raises(PendulumException): + d.nth_of("month", 6, pendulum.MONDAY) + + +def test_nth_of_month_outside_year(): + d = pendulum.date(1975, 12, 5) + + with pytest.raises(PendulumException): + d.nth_of("month", 55, pendulum.MONDAY) + + +def test_nth_of_month_first(): + d = pendulum.date(1975, 12, 5).nth_of("month", 1, pendulum.MONDAY) + + assert_date(d, 1975, 12, 1) + + +def test_2nd_monday_of_month(): + d = pendulum.date(1975, 12, 5).nth_of("month", 2, pendulum.MONDAY) + + assert_date(d, 1975, 12, 8) + + +def test_3rd_wednesday_of_month(): + d = pendulum.date(1975, 12, 5).nth_of("month", 3, 3) + + assert_date(d, 1975, 12, 17) + + +def test_first_day_of_quarter(): + d = pendulum.date(1975, 11, 21).first_of("quarter") + assert_date(d, 1975, 10, 1) + + +def test_first_wednesday_of_quarter(): + d = pendulum.date(1975, 11, 21).first_of("quarter", pendulum.WEDNESDAY) + assert_date(d, 1975, 10, 1) + + +def test_first_friday_of_quarter(): + d = pendulum.date(1975, 11, 21).first_of("quarter", 5) + assert_date(d, 1975, 10, 3) + + +def test_first_of_quarter_from_a_day_that_will_not_exist_in_the_first_month(): + d = pendulum.date(2014, 5, 31).first_of("quarter") + assert_date(d, 2014, 4, 1) + + +def test_last_day_of_quarter(): + d = pendulum.date(1975, 8, 5).last_of("quarter") + assert_date(d, 1975, 9, 30) + + +def test_last_tuesday_of_quarter(): + d = pendulum.date(1975, 8, 5).last_of("quarter", pendulum.TUESDAY) + assert_date(d, 1975, 9, 30) + + +def test_last_friday_of_quarter(): + d = pendulum.date(1975, 8, 5).last_of("quarter", pendulum.FRIDAY) + assert_date(d, 1975, 9, 26) + + +def test_last_day_of_quarter_that_will_not_exist_in_the_last_month(): + d = pendulum.date(2014, 5, 31).last_of("quarter") + assert_date(d, 2014, 6, 30) + + +def test_nth_of_quarter_outside_scope(): + d = pendulum.date(1975, 1, 5) + + with pytest.raises(PendulumException): + d.nth_of("quarter", 20, pendulum.MONDAY) + + +def test_nth_of_quarter_outside_year(): + d = pendulum.date(1975, 1, 5) + + with pytest.raises(PendulumException): + d.nth_of("quarter", 55, pendulum.MONDAY) + + +def test_nth_of_quarter_first(): + d = pendulum.date(1975, 12, 5).nth_of("quarter", 1, pendulum.MONDAY) + + assert_date(d, 1975, 10, 6) + + +def test_nth_of_quarter_from_a_day_that_will_not_exist_in_the_first_month(): + d = pendulum.date(2014, 5, 31).nth_of("quarter", 2, pendulum.MONDAY) + assert_date(d, 2014, 4, 14) + + +def test_2nd_monday_of_quarter(): + d = pendulum.date(1975, 8, 5).nth_of("quarter", 2, pendulum.MONDAY) + assert_date(d, 1975, 7, 14) + + +def test_3rd_wednesday_of_quarter(): + d = pendulum.date(1975, 8, 5).nth_of("quarter", 3, 3) + assert_date(d, 1975, 7, 16) + + +def test_first_day_of_year(): + d = pendulum.date(1975, 11, 21).first_of("year") + assert_date(d, 1975, 1, 1) + + +def test_first_wednesday_of_year(): + d = pendulum.date(1975, 11, 21).first_of("year", pendulum.WEDNESDAY) + assert_date(d, 1975, 1, 1) + + +def test_first_friday_of_year(): + d = pendulum.date(1975, 11, 21).first_of("year", 5) + assert_date(d, 1975, 1, 3) + + +def test_last_day_of_year(): + d = pendulum.date(1975, 8, 5).last_of("year") + assert_date(d, 1975, 12, 31) + + +def test_last_tuesday_of_year(): + d = pendulum.date(1975, 8, 5).last_of("year", pendulum.TUESDAY) + assert_date(d, 1975, 12, 30) + + +def test_last_friday_of_year(): + d = pendulum.date(1975, 8, 5).last_of("year", 5) + assert_date(d, 1975, 12, 26) + + +def test_nth_of_year_outside_scope(): + d = pendulum.date(1975, 1, 5) + + with pytest.raises(PendulumException): + d.nth_of("year", 55, pendulum.MONDAY) + + +def test_nth_of_year_first(): + d = pendulum.date(1975, 12, 5).nth_of("year", 1, pendulum.MONDAY) + + assert_date(d, 1975, 1, 6) + + +def test_2nd_monday_of_year(): + d = pendulum.date(1975, 8, 5).nth_of("year", 2, pendulum.MONDAY) + assert_date(d, 1975, 1, 13) + + +def test_2rd_wednesday_of_year(): + d = pendulum.date(1975, 8, 5).nth_of("year", 3, pendulum.WEDNESDAY) + assert_date(d, 1975, 1, 15) + + +def test_7th_thursday_of_year(): + d = pendulum.date(1975, 8, 31).nth_of("year", 7, pendulum.THURSDAY) + assert_date(d, 1975, 2, 13) + + +def test_first_of_invalid_unit(): + d = pendulum.date(1975, 8, 5) + + with pytest.raises(ValueError): + d.first_of("invalid", 3) + + +def test_last_of_invalid_unit(): + d = pendulum.date(1975, 8, 5) + + with pytest.raises(ValueError): + d.last_of("invalid", 3) + + +def test_nth_of_invalid_unit(): + d = pendulum.date(1975, 8, 5) + + with pytest.raises(ValueError): + d.nth_of("invalid", 3, pendulum.MONDAY) diff --git a/tests/date/test_diff.py b/tests/date/test_diff.py new file mode 100644 index 0000000..56358cc --- /dev/null +++ b/tests/date/test_diff.py @@ -0,0 +1,365 @@ +from __future__ import annotations + +from datetime import date + +import pytest + +import pendulum + + +@pytest.fixture +def today(): + return pendulum.today().date() + + +def test_diff_in_years_positive(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.add(years=1)).in_years() == 1 + + +def test_diff_in_years_negative_with_sign(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.subtract(years=1), False).in_years() == -1 + + +def test_diff_in_years_negative_no_sign(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.subtract(years=1)).in_years() == 1 + + +def test_diff_in_years_vs_default_now(today): + assert today.subtract(years=1).diff().in_years() == 1 + + +def test_diff_in_years_ensure_is_truncated(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.add(years=1).add(months=7)).in_years() == 1 + + +def test_diff_in_months_positive(): + dt = pendulum.date(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.date(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.date(2000, 1, 1) + assert dt.diff(dt.subtract(years=1).add(months=1)).in_months() == 11 + + +def test_diff_in_months_vs_default_now(today): + assert today.subtract(years=1).diff().in_months() == 12 + + +def test_diff_in_months_ensure_is_truncated(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.add(months=1).add(days=16)).in_months() == 1 + + +def test_diff_in_days_positive(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.add(years=1)).in_days() == 366 + + +def test_diff_in_days_negative_with_sign(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.subtract(years=1), False).in_days() == -365 + + +def test_diff_in_days_negative_no_sign(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.subtract(years=1)).in_days() == 365 + + +def test_diff_in_days_vs_default_now(today): + assert today.subtract(weeks=1).diff().in_days() == 7 + + +def test_diff_in_weeks_positive(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.add(years=1)).in_weeks() == 52 + + +def test_diff_in_weeks_negative_with_sign(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.subtract(years=1), False).in_weeks() == -52 + + +def test_diff_in_weeks_negative_no_sign(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.subtract(years=1)).in_weeks() == 52 + + +def test_diff_in_weeks_vs_default_now(today): + assert today.subtract(weeks=1).diff().in_weeks() == 1 + + +def test_diff_in_weeks_ensure_is_truncated(): + dt = pendulum.date(2000, 1, 1) + assert dt.diff(dt.add(weeks=1).subtract(days=1)).in_weeks() == 0 + + +def test_diff_for_humans_now_and_day(today): + assert today.subtract(days=1).diff_for_humans() == "1 day ago" + + +def test_diff_for_humans_now_and_days(today): + assert today.subtract(days=2).diff_for_humans() == "2 days ago" + + +def test_diff_for_humans_now_and_nearly_week(today): + assert today.subtract(days=6).diff_for_humans() == "6 days ago" + + +def test_diff_for_humans_now_and_week(today): + assert today.subtract(weeks=1).diff_for_humans() == "1 week ago" + + +def test_diff_for_humans_now_and_weeks(today): + assert today.subtract(weeks=2).diff_for_humans() == "2 weeks ago" + + +def test_diff_for_humans_now_and_nearly_month(today): + assert today.subtract(weeks=3).diff_for_humans() == "3 weeks ago" + + +def test_diff_for_humans_now_and_month(): + with pendulum.travel_to(pendulum.datetime(2016, 4, 1)): + today = pendulum.today().date() + + assert today.subtract(weeks=4).diff_for_humans() == "4 weeks ago" + assert today.subtract(months=1).diff_for_humans() == "1 month ago" + + with pendulum.travel_to(pendulum.datetime(2017, 3, 1)): + today = pendulum.today().date() + + assert today.subtract(weeks=4).diff_for_humans() == "1 month ago" + + +def test_diff_for_humans_now_and_months(today): + assert today.subtract(months=2).diff_for_humans() == "2 months ago" + + +def test_diff_for_humans_now_and_nearly_year(today): + assert today.subtract(months=11).diff_for_humans() == "11 months ago" + + +def test_diff_for_humans_now_and_year(today): + assert today.subtract(years=1).diff_for_humans() == "1 year ago" + + +def test_diff_for_humans_now_and_years(today): + assert today.subtract(years=2).diff_for_humans() == "2 years ago" + + +def test_diff_for_humans_now_and_future_day(today): + assert today.add(days=1).diff_for_humans() == "in 1 day" + + +def test_diff_for_humans_now_and_future_days(today): + assert today.add(days=2).diff_for_humans() == "in 2 days" + + +def test_diff_for_humans_now_and_nearly_future_week(today): + assert today.add(days=6).diff_for_humans() == "in 6 days" + + +def test_diff_for_humans_now_and_future_week(today): + assert today.add(weeks=1).diff_for_humans() == "in 1 week" + + +def test_diff_for_humans_now_and_future_weeks(today): + assert today.add(weeks=2).diff_for_humans() == "in 2 weeks" + + +def test_diff_for_humans_now_and_nearly_future_month(today): + assert today.add(weeks=3).diff_for_humans() == "in 3 weeks" + + +def test_diff_for_humans_now_and_future_month(): + with pendulum.travel_to(pendulum.datetime(2016, 3, 1)): + today = pendulum.today("UTC").date() + + assert today.add(weeks=4).diff_for_humans() == "in 4 weeks" + assert today.add(months=1).diff_for_humans() == "in 1 month" + + with pendulum.travel_to(pendulum.datetime(2017, 3, 31)): + today = pendulum.today("UTC").date() + + assert today.add(months=1).diff_for_humans() == "in 1 month" + + with pendulum.travel_to(pendulum.datetime(2017, 4, 30)): + today = pendulum.today("UTC").date() + + assert today.add(months=1).diff_for_humans() == "in 1 month" + + with pendulum.travel_to(pendulum.datetime(2017, 1, 31)): + today = pendulum.today("UTC").date() + + assert today.add(weeks=4).diff_for_humans() == "in 1 month" + + +def test_diff_for_humans_now_and_future_months(today): + assert today.add(months=2).diff_for_humans() == "in 2 months" + + +def test_diff_for_humans_now_and_nearly_future_year(today): + assert today.add(months=11).diff_for_humans() == "in 11 months" + + +def test_diff_for_humans_now_and_future_year(today): + assert today.add(years=1).diff_for_humans() == "in 1 year" + + +def test_diff_for_humans_now_and_future_years(today): + assert today.add(years=2).diff_for_humans() == "in 2 years" + + +def test_diff_for_humans_other_and_day(today): + assert today.diff_for_humans(today.add(days=1)) == "1 day before" + + +def test_diff_for_humans_other_and_days(today): + assert today.diff_for_humans(today.add(days=2)) == "2 days before" + + +def test_diff_for_humans_other_and_nearly_week(today): + assert today.diff_for_humans(today.add(days=6)) == "6 days before" + + +def test_diff_for_humans_other_and_week(today): + assert today.diff_for_humans(today.add(weeks=1)) == "1 week before" + + +def test_diff_for_humans_other_and_weeks(today): + assert today.diff_for_humans(today.add(weeks=2)) == "2 weeks before" + + +def test_diff_for_humans_other_and_nearly_month(today): + assert today.diff_for_humans(today.add(weeks=3)) == "3 weeks before" + + +def test_diff_for_humans_other_and_month(): + with pendulum.travel_to(pendulum.datetime(2016, 3, 1)): + today = pendulum.today().date() + + assert today.diff_for_humans(today.add(weeks=4)) == "4 weeks before" + assert today.diff_for_humans(today.add(months=1)) == "1 month before" + + with pendulum.travel_to(pendulum.datetime(2017, 3, 31)): + today = pendulum.today().date() + + assert today.diff_for_humans(today.add(months=1)) == "1 month before" + + with pendulum.travel_to(pendulum.datetime(2017, 4, 30)): + today = pendulum.today().date() + + assert today.diff_for_humans(today.add(months=1)) == "1 month before" + + with pendulum.travel_to(pendulum.datetime(2017, 1, 31)): + today = pendulum.today().date() + + assert today.diff_for_humans(today.add(weeks=4)) == "1 month before" + + +def test_diff_for_humans_other_and_months(today): + assert today.diff_for_humans(today.add(months=2)) == "2 months before" + + +def test_diff_for_humans_other_and_nearly_year(today): + assert today.diff_for_humans(today.add(months=11)) == "11 months before" + + +def test_diff_for_humans_other_and_year(today): + assert today.diff_for_humans(today.add(years=1)) == "1 year before" + + +def test_diff_for_humans_other_and_years(today): + assert today.diff_for_humans(today.add(years=2)) == "2 years before" + + +def test_diff_for_humans_other_and_future_day(today): + assert today.diff_for_humans(today.subtract(days=1)) == "1 day after" + + +def test_diff_for_humans_other_and_future_days(today): + assert today.diff_for_humans(today.subtract(days=2)) == "2 days after" + + +def test_diff_for_humans_other_and_nearly_future_week(today): + assert today.diff_for_humans(today.subtract(days=6)) == "6 days after" + + +def test_diff_for_humans_other_and_future_week(today): + assert today.diff_for_humans(today.subtract(weeks=1)) == "1 week after" + + +def test_diff_for_humans_other_and_future_weeks(today): + assert today.diff_for_humans(today.subtract(weeks=2)) == "2 weeks after" + + +def test_diff_for_humans_other_and_nearly_future_month(today): + assert today.diff_for_humans(today.subtract(weeks=3)) == "3 weeks after" + + +def test_diff_for_humans_other_and_future_month(): + with pendulum.travel_to(pendulum.datetime(2016, 3, 1)): + today = pendulum.today().date() + + assert today.diff_for_humans(today.subtract(weeks=4)) == "4 weeks after" + assert today.diff_for_humans(today.subtract(months=1)) == "1 month after" + + with pendulum.travel_to(pendulum.datetime(2017, 2, 28)): + today = pendulum.today().date() + + assert today.diff_for_humans(today.subtract(weeks=4)) == "1 month after" + + +def test_diff_for_humans_other_and_future_months(today): + assert today.diff_for_humans(today.subtract(months=2)) == "2 months after" + + +def test_diff_for_humans_other_and_nearly_future_year(today): + assert today.diff_for_humans(today.subtract(months=11)) == "11 months after" + + +def test_diff_for_humans_other_and_future_year(today): + assert today.diff_for_humans(today.subtract(years=1)) == "1 year after" + + +def test_diff_for_humans_other_and_future_years(today): + assert today.diff_for_humans(today.subtract(years=2)) == "2 years after" + + +def test_diff_for_humans_absolute_days(today): + assert today.diff_for_humans(today.subtract(days=2), True) == "2 days" + assert today.diff_for_humans(today.add(days=2), True) == "2 days" + + +def test_diff_for_humans_absolute_weeks(today): + assert today.diff_for_humans(today.subtract(weeks=2), True) == "2 weeks" + assert today.diff_for_humans(today.add(weeks=2), True) == "2 weeks" + + +def test_diff_for_humans_absolute_months(today): + assert today.diff_for_humans(today.subtract(months=2), True) == "2 months" + assert today.diff_for_humans(today.add(months=2), True) == "2 months" + + +def test_diff_for_humans_absolute_years(today): + assert today.diff_for_humans(today.subtract(years=1), True) == "1 year" + assert today.diff_for_humans(today.add(years=1), True) == "1 year" + + +def test_subtraction(): + d = pendulum.date(2016, 7, 5) + future_dt = date(2016, 7, 6) + future = d.add(days=1) + + assert (future - d).total_seconds() == 86400 + assert (future_dt - d).total_seconds() == 86400 diff --git a/tests/date/test_fluent_setters.py b/tests/date/test_fluent_setters.py new file mode 100644 index 0000000..c76cc2f --- /dev/null +++ b/tests/date/test_fluent_setters.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +import pendulum + +from tests.conftest import assert_date + + +def test_fluid_year_setter(): + d = pendulum.Date(2016, 10, 20) + new = d.set(year=1995) + + assert_date(new, 1995, 10, 20) + assert new.year == 1995 + + +def test_fluid_month_setter(): + d = pendulum.Date(2016, 7, 2) + new = d.set(month=11) + + assert new.month == 11 + assert d.month == 7 + + +def test_fluid_day_setter(): + d = pendulum.Date(2016, 7, 2) + new = d.set(day=9) + + assert new.day == 9 + assert d.day == 2 diff --git a/tests/date/test_getters.py b/tests/date/test_getters.py new file mode 100644 index 0000000..a492794 --- /dev/null +++ b/tests/date/test_getters.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +import pendulum + + +def test_year(): + d = pendulum.Date(1234, 5, 6) + assert d.year == 1234 + + +def test_month(): + d = pendulum.Date(1234, 5, 6) + assert d.month == 5 + + +def test_day(): + d = pendulum.Date(1234, 5, 6) + assert d.day == 6 + + +def test_day_of_week(): + d = pendulum.Date(2012, 5, 7) + assert d.day_of_week == pendulum.MONDAY + + +def test_day_of_year(): + d = pendulum.Date(2015, 12, 31) + assert d.day_of_year == 365 + d = pendulum.Date(2016, 12, 31) + assert d.day_of_year == 366 + + +def test_days_in_month(): + d = pendulum.Date(2012, 5, 7) + assert d.days_in_month == 31 + + +def test_age(): + d = pendulum.Date.today() + assert d.age == 0 + assert d.add(years=1).age == -1 + assert d.subtract(years=1).age == 1 + + +def test_is_leap_year(): + assert pendulum.Date(2012, 1, 1).is_leap_year() + assert not pendulum.Date(2011, 1, 1).is_leap_year() + + +def test_is_long_year(): + assert pendulum.Date(2015, 1, 1).is_long_year() + assert not pendulum.Date(2016, 1, 1).is_long_year() + + +def test_week_of_month(): + assert pendulum.Date(2012, 9, 30).week_of_month == 5 + assert pendulum.Date(2012, 9, 28).week_of_month == 5 + assert pendulum.Date(2012, 9, 20).week_of_month == 4 + assert pendulum.Date(2012, 9, 8).week_of_month == 2 + assert pendulum.Date(2012, 9, 1).week_of_month == 1 + assert pendulum.date(2020, 1, 1).week_of_month == 1 + assert pendulum.date(2020, 1, 7).week_of_month == 2 + assert pendulum.date(2020, 1, 14).week_of_month == 3 + + +def test_week_of_year_first_week(): + assert pendulum.Date(2012, 1, 1).week_of_year == 52 + assert pendulum.Date(2012, 1, 2).week_of_year == 1 + + +def test_week_of_year_last_week(): + assert pendulum.Date(2012, 12, 30).week_of_year == 52 + assert pendulum.Date(2012, 12, 31).week_of_year == 1 + + +def test_is_future(): + d = pendulum.Date.today() + assert not d.is_future() + d = d.add(days=1) + assert d.is_future() + + +def test_is_past(): + d = pendulum.Date.today() + assert not d.is_past() + d = d.subtract(days=1) + assert d.is_past() diff --git a/tests/date/test_start_end_of.py b/tests/date/test_start_end_of.py new file mode 100644 index 0000000..f1b4412 --- /dev/null +++ b/tests/date/test_start_end_of.py @@ -0,0 +1,252 @@ +from __future__ import annotations + +import pytest + +import pendulum + +from pendulum import Date +from tests.conftest import assert_date + + +def test_start_of_day(): + d = Date.today() + new = d.start_of("day") + assert isinstance(new, Date) + assert_date(new, d.year, d.month, d.day) + + +def test_end_of_day(): + d = Date.today() + new = d.end_of("day") + assert isinstance(new, Date) + assert_date(new, d.year, d.month, d.day) + + +def test_start_of_week(): + d = Date(2016, 10, 20) + new = d.start_of("week") + assert isinstance(new, Date) + assert_date(new, d.year, d.month, 17) + + +def test_end_of_week(): + d = Date(2016, 10, 20) + new = d.end_of("week") + assert isinstance(new, Date) + assert_date(new, d.year, d.month, 23) + + +def test_start_of_month_is_fluid(): + d = Date.today() + assert isinstance(d.start_of("month"), Date) + + +def test_start_of_month_from_now(): + d = Date.today() + new = d.start_of("month") + assert_date(new, d.year, d.month, 1) + + +def test_start_of_month_from_last_day(): + d = Date(2000, 1, 31) + new = d.start_of("month") + assert_date(new, 2000, 1, 1) + + +def test_start_of_year_is_fluid(): + d = Date.today() + new = d.start_of("year") + assert isinstance(new, Date) + + +def test_start_of_year_from_now(): + d = Date.today() + new = d.start_of("year") + assert_date(new, d.year, 1, 1) + + +def test_start_of_year_from_first_day(): + d = Date(2000, 1, 1) + new = d.start_of("year") + assert_date(new, 2000, 1, 1) + + +def test_start_of_year_from_last_day(): + d = Date(2000, 12, 31) + new = d.start_of("year") + assert_date(new, 2000, 1, 1) + + +def test_end_of_month_is_fluid(): + d = Date.today() + assert isinstance(d.end_of("month"), Date) + + +def test_end_of_month_from_now(): + d = Date.today().start_of("month") + new = d.start_of("month") + assert_date(new, d.year, d.month, 1) + + +def test_end_of_month(): + d = Date(2000, 1, 1).end_of("month") + new = d.end_of("month") + assert_date(new, 2000, 1, 31) + + +def test_end_of_month_from_last_day(): + d = Date(2000, 1, 31) + new = d.end_of("month") + assert_date(new, 2000, 1, 31) + + +def test_end_of_year_is_fluid(): + d = Date.today() + assert isinstance(d.end_of("year"), Date) + + +def test_end_of_year_from_now(): + d = Date.today().end_of("year") + new = d.end_of("year") + assert_date(new, d.year, 12, 31) + + +def test_end_of_year_from_first_day(): + d = Date(2000, 1, 1) + new = d.end_of("year") + assert_date(new, 2000, 12, 31) + + +def test_end_of_year_from_last_day(): + d = Date(2000, 12, 31) + new = d.end_of("year") + assert_date(new, 2000, 12, 31) + + +def test_start_of_decade_is_fluid(): + d = Date.today() + assert isinstance(d.start_of("decade"), Date) + + +def test_start_of_decade_from_now(): + d = Date.today() + new = d.start_of("decade") + assert_date(new, d.year - d.year % 10, 1, 1) + + +def test_start_of_decade_from_first_day(): + d = Date(2000, 1, 1) + new = d.start_of("decade") + assert_date(new, 2000, 1, 1) + + +def test_start_of_decade_from_last_day(): + d = Date(2009, 12, 31) + new = d.start_of("decade") + assert_date(new, 2000, 1, 1) + + +def test_end_of_decade_is_fluid(): + d = Date.today() + assert isinstance(d.end_of("decade"), Date) + + +def test_end_of_decade_from_now(): + d = Date.today() + new = d.end_of("decade") + assert_date(new, d.year - d.year % 10 + 9, 12, 31) + + +def test_end_of_decade_from_first_day(): + d = Date(2000, 1, 1) + new = d.end_of("decade") + assert_date(new, 2009, 12, 31) + + +def test_end_of_decade_from_last_day(): + d = Date(2009, 12, 31) + new = d.end_of("decade") + assert_date(new, 2009, 12, 31) + + +def test_start_of_century_is_fluid(): + d = Date.today() + assert isinstance(d.start_of("century"), Date) + + +def test_start_of_century_from_now(): + d = Date.today() + new = d.start_of("century") + assert_date(new, d.year - d.year % 100 + 1, 1, 1) + + +def test_start_of_century_from_first_day(): + d = Date(2001, 1, 1) + new = d.start_of("century") + assert_date(new, 2001, 1, 1) + + +def test_start_of_century_from_last_day(): + d = Date(2100, 12, 31) + new = d.start_of("century") + assert_date(new, 2001, 1, 1) + + +def test_end_of_century_is_fluid(): + d = Date.today() + assert isinstance(d.end_of("century"), Date) + + +def test_end_of_century_from_now(): + now = Date.today() + d = now.end_of("century") + assert_date(d, now.year - now.year % 100 + 100, 12, 31) + + +def test_end_of_century_from_first_day(): + d = Date(2001, 1, 1) + new = d.end_of("century") + assert_date(new, 2100, 12, 31) + + +def test_end_of_century_from_last_day(): + d = Date(2100, 12, 31) + new = d.end_of("century") + assert_date(new, 2100, 12, 31) + + +def test_average_is_fluid(): + d = Date.today().average() + assert isinstance(d, Date) + + +def test_average_from_same(): + d1 = pendulum.date(2000, 1, 31) + d2 = pendulum.date(2000, 1, 31).average(d1) + assert_date(d2, 2000, 1, 31) + + +def test_average_from_greater(): + d1 = pendulum.date(2000, 1, 1) + d2 = pendulum.date(2009, 12, 31).average(d1) + assert_date(d2, 2004, 12, 31) + + +def test_average_from_lower(): + d1 = pendulum.date(2009, 12, 31) + d2 = pendulum.date(2000, 1, 1).average(d1) + assert_date(d2, 2004, 12, 31) + + +def test_start_of(): + d = pendulum.date(2013, 3, 31) + + with pytest.raises(ValueError): + d.start_of("invalid") + + +def test_end_of_invalid_unit(): + d = pendulum.date(2013, 3, 31) + + with pytest.raises(ValueError): + d.end_of("invalid") diff --git a/tests/date/test_strings.py b/tests/date/test_strings.py new file mode 100644 index 0000000..f373581 --- /dev/null +++ b/tests/date/test_strings.py @@ -0,0 +1,48 @@ +from __future__ import annotations + +import pendulum + + +def test_to_string(): + d = pendulum.Date(2016, 10, 16) + assert str(d) == "2016-10-16" + + +def test_to_date_string(): + d = pendulum.Date(1975, 12, 25) + assert d.to_date_string() == "1975-12-25" + + +def test_to_formatted_date_string(): + d = pendulum.Date(1975, 12, 25) + assert d.to_formatted_date_string() == "Dec 25, 1975" + + +def test_repr(): + d = pendulum.Date(1975, 12, 25) + + assert repr(d) == "Date(1975, 12, 25)" + assert d.__repr__() == "Date(1975, 12, 25)" + + +def test_format_with_locale(): + d = pendulum.Date(1975, 12, 25) + expected = "jeudi 25e jour de décembre 1975" + assert d.format("dddd Do [jour de] MMMM YYYY", locale="fr") == expected + + +def test_strftime(): + d = pendulum.Date(1975, 12, 25) + assert d.strftime("%d") == "25" + + +def test_for_json(): + d = pendulum.Date(1975, 12, 25) + assert d.for_json() == "1975-12-25" + + +def test_format(): + d = pendulum.Date(1975, 12, 25) + assert f"{d}" == "1975-12-25" + assert f"{d:YYYY}" == "1975" + assert f"{d:%Y}" == "1975" diff --git a/tests/date/test_sub.py b/tests/date/test_sub.py new file mode 100644 index 0000000..33855a4 --- /dev/null +++ b/tests/date/test_sub.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +from datetime import datetime +from datetime import timedelta + +import pytest + +import pendulum + +from tests.conftest import assert_date + + +def test_subtract_years_positive(): + assert pendulum.date(1975, 1, 1).subtract(years=1).year == 1974 + + +def test_subtract_years_zero(): + assert pendulum.date(1975, 1, 1).subtract(years=0).year == 1975 + + +def test_subtract_years_negative(): + assert pendulum.date(1975, 1, 1).subtract(years=-1).year == 1976 + + +def test_subtract_months_positive(): + assert pendulum.date(1975, 1, 1).subtract(months=1).month == 12 + + +def test_subtract_months_zero(): + assert pendulum.date(1975, 12, 1).subtract(months=0).month == 12 + + +def test_subtract_months_negative(): + assert pendulum.date(1975, 11, 1).subtract(months=-1).month == 12 + + +def test_subtract_days_positive(): + assert pendulum.Date(1975, 6, 1).subtract(days=1).day == 31 + + +def test_subtract_days_zero(): + assert pendulum.Date(1975, 5, 31).subtract(days=0).day == 31 + + +def test_subtract_days_negative(): + assert pendulum.Date(1975, 5, 30).subtract(days=-1).day == 31 + + +def test_subtract_days_max(): + delta = pendulum.now() - pendulum.instance(datetime.min) + assert pendulum.now().subtract(days=delta.days - 1).year == 1 + + +def test_subtract_weeks_positive(): + assert pendulum.Date(1975, 5, 28).subtract(weeks=1).day == 21 + + +def test_subtract_weeks_zero(): + assert pendulum.Date(1975, 5, 21).subtract(weeks=0).day == 21 + + +def test_subtract_weeks_negative(): + assert pendulum.Date(1975, 5, 14).subtract(weeks=-1).day == 21 + + +def test_subtract_timedelta(): + delta = timedelta(days=18) + d = pendulum.date(2015, 3, 14) + + new = d - delta + assert isinstance(new, pendulum.Date) + assert_date(new, 2015, 2, 24) + + +def test_subtract_duration(): + delta = pendulum.duration(years=2, months=3, days=18) + d = pendulum.date(2015, 3, 14) + + new = d - delta + assert_date(new, 2012, 11, 26) + + +def test_addition_invalid_type(): + d = pendulum.date(2015, 3, 14) + + with pytest.raises(TypeError): + d - "ab" + + with pytest.raises(TypeError): + "ab" - d diff --git a/tests/datetime/__init__.py b/tests/datetime/__init__.py new file mode 100644 index 0000000..e69de29 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) diff --git a/tests/duration/__init__.py b/tests/duration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/duration/test_add_sub.py b/tests/duration/test_add_sub.py new file mode 100644 index 0000000..193a493 --- /dev/null +++ b/tests/duration/test_add_sub.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +from datetime import timedelta + +import pendulum + +from tests.conftest import assert_duration + + +def test_add_interval(): + p1 = pendulum.duration(days=23, seconds=32) + p2 = pendulum.duration(days=12, seconds=30) + + p = p1 + p2 + assert_duration(p, 0, 0, 5, 0, 0, 1, 2) + + +def test_add_timedelta(): + p1 = pendulum.duration(days=23, seconds=32) + p2 = timedelta(days=12, seconds=30) + + p = p1 + p2 + assert_duration(p, 0, 0, 5, 0, 0, 1, 2) + + +def test_add_unsupported(): + p = pendulum.duration(days=23, seconds=32) + assert NotImplemented == p.__add__(5) + + +def test_sub_interval(): + p1 = pendulum.duration(days=23, seconds=32) + p2 = pendulum.duration(days=12, seconds=28) + + p = p1 - p2 + assert_duration(p, 0, 0, 1, 4, 0, 0, 4) + + +def test_sub_timedelta(): + p1 = pendulum.duration(days=23, seconds=32) + p2 = timedelta(days=12, seconds=28) + + p = p1 - p2 + assert_duration(p, 0, 0, 1, 4, 0, 0, 4) + + +def test_sub_unsupported(): + p = pendulum.duration(days=23, seconds=32) + assert NotImplemented == p.__sub__(5) + + +def test_neg(): + p = pendulum.duration(days=23, seconds=32) + assert_duration(-p, 0, 0, -3, -2, 0, 0, -32) diff --git a/tests/duration/test_arithmetic.py b/tests/duration/test_arithmetic.py new file mode 100644 index 0000000..cba4d39 --- /dev/null +++ b/tests/duration/test_arithmetic.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +import pendulum + +from tests.conftest import assert_duration + + +def test_multiply(): + it = pendulum.duration(days=6, seconds=34, microseconds=522222) + mul = it * 2 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 1, 5, 0, 1, 9, 44444) + + it = pendulum.duration(days=6, seconds=34, microseconds=522222) + mul = 2 * it + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 1, 5, 0, 1, 9, 44444) + + it = pendulum.duration( + years=2, months=3, weeks=4, days=6, seconds=34, microseconds=522222 + ) + mul = 2 * it + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 4, 6, 9, 5, 0, 1, 9, 44444) + + +def test_divide(): + it = pendulum.duration(days=2, seconds=34, microseconds=522222) + mul = it / 2 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 0, 1, 0, 0, 17, 261111) + + it = pendulum.duration(days=2, seconds=35, microseconds=522222) + mul = it / 2 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 0, 1, 0, 0, 17, 761111) + + it = pendulum.duration(days=2, seconds=35, microseconds=522222) + mul = it / 1.1 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 0, 1, 19, 38, 43, 202020) + + it = pendulum.duration(years=2, months=4, days=2, seconds=35, microseconds=522222) + mul = it / 2 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 1, 2, 0, 1, 0, 0, 17, 761111) + + it = pendulum.duration(years=2, months=4, days=2, seconds=35, microseconds=522222) + mul = it / 2.0 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 1, 2, 0, 1, 0, 0, 17, 761111) + + +def test_floor_divide(): + it = pendulum.duration(days=2, seconds=34, microseconds=522222) + mul = it // 2 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 0, 1, 0, 0, 17, 261111) + + it = pendulum.duration(days=2, seconds=35, microseconds=522222) + mul = it // 3 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 0, 0, 16, 0, 11, 840740) + + it = pendulum.duration(years=2, months=4, days=2, seconds=34, microseconds=522222) + mul = it // 2 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 1, 2, 0, 1, 0, 0, 17, 261111) + + it = pendulum.duration(years=2, months=4, days=2, seconds=35, microseconds=522222) + mul = it // 3 + + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 1, 0, 0, 16, 0, 11, 840740) diff --git a/tests/duration/test_behavior.py b/tests/duration/test_behavior.py new file mode 100644 index 0000000..a97bbde --- /dev/null +++ b/tests/duration/test_behavior.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +import pickle + +from datetime import timedelta + +import pendulum + + +def test_pickle(): + it = pendulum.duration(days=3, seconds=2456, microseconds=123456) + s = pickle.dumps(it) + it2 = pickle.loads(s) + + assert it == it2 + + +def test_comparison_to_timedelta(): + duration = pendulum.duration(days=3) + + assert duration < timedelta(days=4) diff --git a/tests/duration/test_construct.py b/tests/duration/test_construct.py new file mode 100644 index 0000000..aaa5390 --- /dev/null +++ b/tests/duration/test_construct.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +from datetime import timedelta + +import pytest + +import pendulum + +from pendulum.duration import AbsoluteDuration +from tests.conftest import assert_duration + + +def test_defaults(): + pi = pendulum.duration() + assert_duration(pi, 0, 0, 0, 0, 0, 0, 0) + + +def test_years(): + pi = pendulum.duration(years=2) + assert_duration(pi, years=2, weeks=0) + assert pi.days == 730 + assert pi.total_seconds() == 63072000 + + +def test_months(): + pi = pendulum.duration(months=3) + assert_duration(pi, months=3, weeks=0) + assert pi.days == 90 + assert pi.total_seconds() == 7776000 + + +def test_weeks(): + pi = pendulum.duration(days=365) + assert_duration(pi, weeks=52) + + pi = pendulum.duration(days=13) + assert_duration(pi, weeks=1) + + +def test_days(): + pi = pendulum.duration(days=6) + assert_duration(pi, 0, 0, 0, 6, 0, 0, 0) + + pi = pendulum.duration(days=16) + assert_duration(pi, 0, 0, 2, 2, 0, 0, 0) + + +def test_hours(): + pi = pendulum.duration(seconds=3600 * 3) + assert_duration(pi, 0, 0, 0, 0, 3, 0, 0) + + +def test_minutes(): + pi = pendulum.duration(seconds=60 * 3) + assert_duration(pi, 0, 0, 0, 0, 0, 3, 0) + + pi = pendulum.duration(seconds=60 * 3 + 12) + assert_duration(pi, 0, 0, 0, 0, 0, 3, 12) + + +def test_all(): + pi = pendulum.duration( + years=2, months=3, days=1177, seconds=7284, microseconds=1000000 + ) + assert_duration(pi, 2, 3, 168, 1, 2, 1, 25) + assert pi.days == 1997 + assert pi.seconds == 7285 + + +def test_absolute_interval(): + pi = AbsoluteDuration(days=-1177, seconds=-7284, microseconds=-1000001) + assert_duration(pi, 0, 0, 168, 1, 2, 1, 25) + assert pi.microseconds == 1 + assert pi.invert + + +def test_invert(): + pi = pendulum.duration(days=1177, seconds=7284, microseconds=1000000) + assert not pi.invert + + pi = pendulum.duration(days=-1177, seconds=-7284, microseconds=-1000000) + assert pi.invert + + +def test_as_timedelta(): + pi = pendulum.duration(seconds=3456.123456) + assert_duration(pi, 0, 0, 0, 0, 0, 57, 36, 123456) + delta = pi.as_timedelta() + assert isinstance(delta, timedelta) + assert delta.total_seconds() == 3456.123456 + assert delta.seconds == 3456 + + +def test_float_years_and_months(): + with pytest.raises(ValueError): + pendulum.duration(years=1.5) + + with pytest.raises(ValueError): + pendulum.duration(months=1.5) diff --git a/tests/duration/test_in_methods.py b/tests/duration/test_in_methods.py new file mode 100644 index 0000000..4527257 --- /dev/null +++ b/tests/duration/test_in_methods.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +import pendulum + + +def test_in_weeks(): + it = pendulum.duration(days=17) + assert it.in_weeks() == 2 + + +def test_in_days(): + it = pendulum.duration(days=3) + assert it.in_days() == 3 + + +def test_in_hours(): + it = pendulum.duration(days=3, minutes=72) + assert it.in_hours() == 73 + + +def test_in_minutes(): + it = pendulum.duration(minutes=6, seconds=72) + assert it.in_minutes() == 7 + + +def test_in_seconds(): + it = pendulum.duration(seconds=72) + assert it.in_seconds() == 72 diff --git a/tests/duration/test_in_words.py b/tests/duration/test_in_words.py new file mode 100644 index 0000000..c0a1a1f --- /dev/null +++ b/tests/duration/test_in_words.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +import pendulum + + +def test_week(): + assert pendulum.duration(days=364).in_words() == "52 weeks" + assert pendulum.duration(days=7).in_words() == "1 week" + + +def test_week_to_string(): + assert str(pendulum.duration(days=364)) == "52 weeks" + assert str(pendulum.duration(days=7)) == "1 week" + + +def test_weeks_and_day(): + assert pendulum.duration(days=365).in_words() == "52 weeks 1 day" + + +def test_all(): + pi = pendulum.duration( + years=2, months=3, days=1177, seconds=7284, microseconds=1000000 + ) + + expected = "2 years 3 months 168 weeks 1 day 2 hours 1 minute 25 seconds" + assert pi.in_words() == expected + + +def test_in_french(): + pi = pendulum.duration( + years=2, months=3, days=1177, seconds=7284, microseconds=1000000 + ) + + expected = "2 ans 3 mois 168 semaines 1 jour 2 heures 1 minute 25 secondes" + assert pi.in_words(locale="fr") == expected + + +def test_repr(): + pi = pendulum.duration( + years=2, months=3, days=1177, seconds=7284, microseconds=1000000 + ) + + expected = ( + "Duration(years=2, months=3, weeks=168, days=1, hours=2, minutes=1, seconds=25)" + ) + assert repr(pi) == expected + + +def test_singular_negative_values(): + pi = pendulum.duration(days=-1) + + assert pi.in_words() == "-1 day" + + +def test_separator(): + pi = pendulum.duration(days=1177, seconds=7284, microseconds=1000000) + + expected = "168 weeks, 1 day, 2 hours, 1 minute, 25 seconds" + assert pi.in_words(separator=", ") == expected + + +def test_subseconds(): + pi = pendulum.duration(microseconds=123456) + + assert pi.in_words() == "0.12 second" + + +def test_subseconds_with_seconds(): + pi = pendulum.duration(seconds=12, microseconds=123456) + + assert pi.in_words() == "12 seconds" + + +def test_duration_with_all_zero_values(): + pi = pendulum.duration() + + assert pi.in_words() == "0 microseconds" diff --git a/tests/duration/test_total_methods.py b/tests/duration/test_total_methods.py new file mode 100644 index 0000000..aabcd6c --- /dev/null +++ b/tests/duration/test_total_methods.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +import pendulum + + +def test_in_weeks(): + it = pendulum.duration(days=17) + assert round(it.total_weeks(), 2) == 2.43 + + +def test_in_days(): + it = pendulum.duration(days=3) + assert it.total_days() == 3 + + +def test_in_hours(): + it = pendulum.duration(days=3, minutes=72) + assert it.total_hours() == 73.2 + + +def test_in_minutes(): + it = pendulum.duration(minutes=6, seconds=72) + assert it.total_minutes() == 7.2 + + +def test_in_seconds(): + it = pendulum.duration(seconds=72, microseconds=123456) + assert it.total_seconds() == 72.123456 diff --git a/tests/fixtures/__init__.py b/tests/fixtures/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/fixtures/tz/Paris b/tests/fixtures/tz/Paris new file mode 100644 index 0000000..cf6e2e2 Binary files /dev/null and b/tests/fixtures/tz/Paris differ diff --git a/tests/fixtures/tz/clock/etc/sysconfig/clock b/tests/fixtures/tz/clock/etc/sysconfig/clock new file mode 100644 index 0000000..285e68b --- /dev/null +++ b/tests/fixtures/tz/clock/etc/sysconfig/clock @@ -0,0 +1 @@ +ZONE="/usr/share/zoneinfo/Europe/Zurich" diff --git a/tests/fixtures/tz/symlink/etc/localtime b/tests/fixtures/tz/symlink/etc/localtime new file mode 120000 index 0000000..d9726ef --- /dev/null +++ b/tests/fixtures/tz/symlink/etc/localtime @@ -0,0 +1 @@ +../usr/share/zoneinfo/Europe/Paris \ No newline at end of file diff --git a/tests/fixtures/tz/symlink/usr/share/zoneinfo/Europe/Paris b/tests/fixtures/tz/symlink/usr/share/zoneinfo/Europe/Paris new file mode 100644 index 0000000..cf6e2e2 Binary files /dev/null and b/tests/fixtures/tz/symlink/usr/share/zoneinfo/Europe/Paris differ diff --git a/tests/fixtures/tz/timezone_dir/etc/localtime b/tests/fixtures/tz/timezone_dir/etc/localtime new file mode 120000 index 0000000..d9726ef --- /dev/null +++ b/tests/fixtures/tz/timezone_dir/etc/localtime @@ -0,0 +1 @@ +../usr/share/zoneinfo/Europe/Paris \ No newline at end of file diff --git a/tests/fixtures/tz/timezone_dir/etc/timezone/blank.md b/tests/fixtures/tz/timezone_dir/etc/timezone/blank.md new file mode 100644 index 0000000..a3a9320 --- /dev/null +++ b/tests/fixtures/tz/timezone_dir/etc/timezone/blank.md @@ -0,0 +1,5 @@ +# Blank file + +Necessary for environments, which not handle empty folder synchronization well, to be sure the parent folder is created. + +The `/etc/timezone` folder is necessary to ensure that the package not fail if that folder exists. diff --git a/tests/fixtures/tz/timezone_dir/usr/share/zoneinfo/Europe/Paris b/tests/fixtures/tz/timezone_dir/usr/share/zoneinfo/Europe/Paris new file mode 100644 index 0000000..cf6e2e2 Binary files /dev/null and b/tests/fixtures/tz/timezone_dir/usr/share/zoneinfo/Europe/Paris differ diff --git a/tests/formatting/__init__.py b/tests/formatting/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/formatting/test_formatter.py b/tests/formatting/test_formatter.py new file mode 100644 index 0000000..76c7a7f --- /dev/null +++ b/tests/formatting/test_formatter.py @@ -0,0 +1,263 @@ +from __future__ import annotations + +import pytest + +import pendulum + +from pendulum.formatting import Formatter +from pendulum.locales.locale import Locale + + +@pytest.fixture(autouse=True) +def setup(): + Locale._cache["dummy"] = {} + + yield + + del Locale._cache["dummy"] + + +def test_year_tokens(): + d = pendulum.datetime(2009, 1, 14, 15, 25, 50, 123456) + f = Formatter() + + assert f.format(d, "YYYY") == "2009" + assert f.format(d, "YY") == "09" + assert f.format(d, "Y") == "2009" + + +def test_quarter_tokens(): + f = Formatter() + d = pendulum.datetime(1985, 1, 4) + assert f.format(d, "Q") == "1" + + d = pendulum.datetime(2029, 8, 1) + assert f.format(d, "Q") == "3" + + d = pendulum.datetime(1985, 1, 4) + assert f.format(d, "Qo") == "1st" + + d = pendulum.datetime(2029, 8, 1) + assert f.format(d, "Qo") == "3rd" + + d = pendulum.datetime(1985, 1, 4) + assert f.format(d, "Qo", locale="fr") == "1er" + + d = pendulum.datetime(2029, 8, 1) + assert f.format(d, "Qo", locale="fr") == "3e" + + +def test_month_tokens(): + f = Formatter() + d = pendulum.datetime(2016, 3, 24) + assert f.format(d, "MM") == "03" + assert f.format(d, "M") == "3" + + assert f.format(d, "MMM") == "Mar" + assert f.format(d, "MMMM") == "March" + assert f.format(d, "Mo") == "3rd" + + assert f.format(d, "MMM", locale="fr") == "mars" + assert f.format(d, "MMMM", locale="fr") == "mars" + assert f.format(d, "Mo", locale="fr") == "3e" + + +def test_day_tokens(): + f = Formatter() + d = pendulum.datetime(2016, 3, 7) + assert f.format(d, "DD") == "07" + assert f.format(d, "D") == "7" + + assert f.format(d, "Do") == "7th" + assert f.format(d.first_of("month"), "Do") == "1st" + + assert f.format(d, "Do", locale="fr") == "7e" + assert f.format(d.first_of("month"), "Do", locale="fr") == "1er" + + +def test_day_of_year(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28) + assert f.format(d, "DDDD") == "241" + assert f.format(d, "DDD") == "241" + assert f.format(d.start_of("year"), "DDDD") == "001" + assert f.format(d.start_of("year"), "DDD") == "1" + + assert f.format(d, "DDDo") == "241st" + assert f.format(d.add(days=3), "DDDo") == "244th" + + assert f.format(d, "DDDo", locale="fr") == "241e" + assert f.format(d.add(days=3), "DDDo", locale="fr") == "244e" + + +def test_week_of_year(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28) + + assert f.format(d, "wo") == "34th" + + +def test_day_of_week(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28) + assert f.format(d, "d") == "0" + + assert f.format(d, "dd") == "Su" + assert f.format(d, "ddd") == "Sun" + assert f.format(d, "dddd") == "Sunday" + + assert f.format(d, "dd", locale="fr") == "di" + assert f.format(d, "ddd", locale="fr") == "dim." + assert f.format(d, "dddd", locale="fr") == "dimanche" + + assert f.format(d, "do") == "0th" + + +def test_day_of_iso_week(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28) + assert f.format(d, "E") == "7" + + +def test_am_pm(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 23) + assert f.format(d, "A") == "PM" + assert f.format(d.set(hour=11), "A") == "AM" + + +def test_hour(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 7) + assert f.format(d, "H") == "7" + assert f.format(d, "HH") == "07" + + d = pendulum.datetime(2016, 8, 28, 0) + assert f.format(d, "h") == "12" + assert f.format(d, "hh") == "12" + + +def test_minute(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 7, 3) + assert f.format(d, "m") == "3" + assert f.format(d, "mm") == "03" + + +def test_second(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 7, 3, 6) + assert f.format(d, "s") == "6" + assert f.format(d, "ss") == "06" + + +def test_fractional_second(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456) + assert f.format(d, "S") == "1" + assert f.format(d, "SS") == "12" + assert f.format(d, "SSS") == "123" + assert f.format(d, "SSSS") == "1234" + assert f.format(d, "SSSSS") == "12345" + assert f.format(d, "SSSSSS") == "123456" + + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 0) + assert f.format(d, "S") == "0" + assert f.format(d, "SS") == "00" + assert f.format(d, "SSS") == "000" + assert f.format(d, "SSSS") == "0000" + assert f.format(d, "SSSSS") == "00000" + assert f.format(d, "SSSSSS") == "000000" + + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123) + assert f.format(d, "S") == "0" + assert f.format(d, "SS") == "00" + assert f.format(d, "SSS") == "000" + assert f.format(d, "SSSS") == "0001" + assert f.format(d, "SSSSS") == "00012" + assert f.format(d, "SSSSSS") == "000123" + + +def test_timezone(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456, tz="Europe/Paris") + assert f.format(d, "zz") == "CEST" + assert f.format(d, "z") == "Europe/Paris" + + d = pendulum.datetime(2016, 1, 28, 7, 3, 6, 123456, tz="Europe/Paris") + assert f.format(d, "zz") == "CET" + assert f.format(d, "z") == "Europe/Paris" + + +def test_timezone_offset(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456, tz="Europe/Paris") + assert f.format(d, "ZZ") == "+0200" + assert f.format(d, "Z") == "+02:00" + + d = pendulum.datetime(2016, 1, 28, 7, 3, 6, 123456, tz="Europe/Paris") + assert f.format(d, "ZZ") == "+0100" + assert f.format(d, "Z") == "+01:00" + + d = pendulum.datetime(2016, 1, 28, 7, 3, 6, 123456, tz="America/Guayaquil") + assert f.format(d, "ZZ") == "-0500" + assert f.format(d, "Z") == "-05:00" + + +def test_timestamp(): + f = Formatter() + d = pendulum.datetime(1970, 1, 1) + assert f.format(d, "X") == "0" + assert f.format(d.add(days=1), "X") == "86400" + + +def test_timestamp_milliseconds(): + f = Formatter() + d = pendulum.datetime(1970, 1, 1) + assert f.format(d, "x") == "0" + assert f.format(d.add(days=1), "x") == "86400000" + assert f.format(d.add(days=1, microseconds=129123), "x") == "86400129" + + +def test_date_formats(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456) + assert f.format(d, "LT") == "7:03 AM" + assert f.format(d, "LTS") == "7:03:06 AM" + assert f.format(d, "L") == "08/28/2016" + assert f.format(d, "LL") == "August 28, 2016" + assert f.format(d, "LLL") == "August 28, 2016 7:03 AM" + assert f.format(d, "LLLL") == "Sunday, August 28, 2016 7:03 AM" + + assert f.format(d, "LT", locale="fr") == "07:03" + assert f.format(d, "LTS", locale="fr") == "07:03:06" + assert f.format(d, "L", locale="fr") == "28/08/2016" + assert f.format(d, "LL", locale="fr") == "28 août 2016" + assert f.format(d, "LLL", locale="fr") == "28 août 2016 07:03" + assert f.format(d, "LLLL", locale="fr") == "dimanche 28 août 2016 07:03" + + +def test_escape(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28) + assert f.format(d, r"[YYYY] YYYY \[YYYY\]") == "YYYY 2016 [2016]" + assert f.format(d, r"\D D \\D") == "D 28 \\28" + + +def test_date_formats_missing(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456) + + assert f.format(d, "LT", locale="dummy") == "7:03 AM" + assert f.format(d, "LTS", locale="dummy") == "7:03:06 AM" + assert f.format(d, "L", locale="dummy") == "08/28/2016" + assert f.format(d, "LL", locale="dummy") == "August 28, 2016" + assert f.format(d, "LLL", locale="dummy") == "August 28, 2016 7:03 AM" + assert f.format(d, "LLLL", locale="dummy") == "Sunday, August 28, 2016 7:03 AM" + + +def test_unknown_token(): + f = Formatter() + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456) + + assert f.format(d, "J") == "J" diff --git a/tests/helpers/__init__.py b/tests/helpers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/helpers/test_local_time.py b/tests/helpers/test_local_time.py new file mode 100644 index 0000000..0563107 --- /dev/null +++ b/tests/helpers/test_local_time.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +import pendulum + +from pendulum.helpers import local_time + + +def test_local_time_positive_integer(): + d = pendulum.datetime(2016, 8, 7, 12, 34, 56, 123456) + + t = local_time(d.int_timestamp, 0, d.microsecond) + assert d.year == t[0] + assert d.month == t[1] + assert d.day == t[2] + assert d.hour == t[3] + assert d.minute == t[4] + assert d.second == t[5] + assert d.microsecond == t[6] + + +def test_local_time_negative_integer(): + d = pendulum.datetime(1951, 8, 7, 12, 34, 56, 123456) + + t = local_time(d.int_timestamp, 0, d.microsecond) + assert d.year == t[0] + assert d.month == t[1] + assert d.day == t[2] + assert d.hour == t[3] + assert d.minute == t[4] + assert d.second == t[5] + assert d.microsecond == t[6] diff --git a/tests/interval/__init__.py b/tests/interval/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/interval/test_add_subtract.py b/tests/interval/test_add_subtract.py new file mode 100644 index 0000000..88525a3 --- /dev/null +++ b/tests/interval/test_add_subtract.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +import pendulum + + +def test_dst_add(): + start = pendulum.datetime(2017, 3, 7, tz="America/Toronto") + end = start.add(days=6) + period = end - start + new_end = start + period + + assert new_end == end + + +def test_dst_add_non_variable_units(): + start = pendulum.datetime(2013, 3, 31, 1, 30, tz="Europe/Paris") + end = start.add(hours=1) + period = end - start + new_end = start + period + + assert new_end == end + + +def test_dst_subtract(): + start = pendulum.datetime(2017, 3, 7, tz="America/Toronto") + end = start.add(days=6) + period = end - start + new_start = end - period + + assert new_start == start + + +def test_naive_subtract(): + start = pendulum.naive(2013, 3, 31, 1, 30) + end = start.add(hours=1) + period = end - start + new_end = start + period + + assert new_end == end + + +def test_negative_difference_subtract(): + start = pendulum.datetime(2018, 5, 28, 12, 34, 56, 123456) + end = pendulum.datetime(2018, 1, 1) + + period = end - start + new_end = start + period + + assert new_end == end diff --git a/tests/interval/test_arithmetic.py b/tests/interval/test_arithmetic.py new file mode 100644 index 0000000..e5ba01f --- /dev/null +++ b/tests/interval/test_arithmetic.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +import pendulum + +from tests.conftest import assert_duration + + +def test_multiply(): + dt1 = pendulum.DateTime(2016, 8, 7, 12, 34, 56) + dt2 = dt1.add(days=6, seconds=34) + it = pendulum.interval(dt1, dt2) + mul = it * 2 + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 1, 5, 0, 1, 8) + + dt1 = pendulum.DateTime(2016, 8, 7, 12, 34, 56) + dt2 = dt1.add(days=6, seconds=34) + it = pendulum.interval(dt1, dt2) + mul = it * 2 + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 1, 5, 0, 1, 8) + + +def test_divide(): + dt1 = pendulum.DateTime(2016, 8, 7, 12, 34, 56) + dt2 = dt1.add(days=2, seconds=34) + it = pendulum.interval(dt1, dt2) + mul = it / 2 + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 0, 1, 0, 0, 17) + + dt1 = pendulum.DateTime(2016, 8, 7, 12, 34, 56) + dt2 = dt1.add(days=2, seconds=35) + it = pendulum.interval(dt1, dt2) + mul = it / 2 + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 0, 1, 0, 0, 17) + + +def test_floor_divide(): + dt1 = pendulum.DateTime(2016, 8, 7, 12, 34, 56) + dt2 = dt1.add(days=2, seconds=34) + it = pendulum.interval(dt1, dt2) + mul = it // 2 + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 0, 1, 0, 0, 17) + + dt1 = pendulum.DateTime(2016, 8, 7, 12, 34, 56) + dt2 = dt1.add(days=2, seconds=35) + it = pendulum.interval(dt1, dt2) + mul = it // 3 + assert isinstance(mul, pendulum.Duration) + assert_duration(mul, 0, 0, 0, 0, 16, 0, 11) diff --git a/tests/interval/test_behavior.py b/tests/interval/test_behavior.py new file mode 100644 index 0000000..b5e057a --- /dev/null +++ b/tests/interval/test_behavior.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +import pickle + +from datetime import timedelta + +import pendulum + + +def test_pickle(): + dt1 = pendulum.datetime(2016, 11, 18) + dt2 = pendulum.datetime(2016, 11, 20) + + p = pendulum.interval(dt1, dt2) + s = pickle.dumps(p) + p2 = pickle.loads(s) + + assert p.start == p2.start + assert p.end == p2.end + assert p.invert == p2.invert + + p = pendulum.interval(dt2, dt1) + s = pickle.dumps(p) + p2 = pickle.loads(s) + + assert p.start == p2.start + assert p.end == p2.end + assert p.invert == p2.invert + + p = pendulum.interval(dt2, dt1, True) + s = pickle.dumps(p) + p2 = pickle.loads(s) + + assert p.start == p2.start + assert p.end == p2.end + assert p.invert == p2.invert + + +def test_comparison_to_timedelta(): + dt1 = pendulum.datetime(2016, 11, 18) + dt2 = pendulum.datetime(2016, 11, 20) + + period = dt2 - dt1 + + assert period < timedelta(days=4) + + +def test_equality_to_timedelta(): + dt1 = pendulum.datetime(2016, 11, 18) + dt2 = pendulum.datetime(2016, 11, 20) + + period = dt2 - dt1 + + assert period == timedelta(days=2) diff --git a/tests/interval/test_construct.py b/tests/interval/test_construct.py new file mode 100644 index 0000000..024e741 --- /dev/null +++ b/tests/interval/test_construct.py @@ -0,0 +1,121 @@ +from __future__ import annotations + +from datetime import datetime + +import pendulum + +from tests.conftest import assert_datetime + + +def test_with_datetimes(): + dt1 = datetime(2000, 1, 1) + dt2 = datetime(2000, 1, 31) + p = pendulum.interval(dt1, dt2) + + assert isinstance(p.start, pendulum.DateTime) + assert isinstance(p.end, pendulum.DateTime) + assert_datetime(p.start, 2000, 1, 1) + assert_datetime(p.end, 2000, 1, 31) + + +def test_with_pendulum(): + dt1 = pendulum.DateTime(2000, 1, 1) + dt2 = pendulum.DateTime(2000, 1, 31) + p = pendulum.interval(dt1, dt2) + + assert_datetime(p.start, 2000, 1, 1) + assert_datetime(p.end, 2000, 1, 31) + + +def test_inverted(): + dt1 = pendulum.DateTime(2000, 1, 1) + dt2 = pendulum.DateTime(2000, 1, 31) + p = pendulum.interval(dt2, dt1) + + assert_datetime(p.start, 2000, 1, 31) + assert_datetime(p.end, 2000, 1, 1) + + +def test_inverted_and_absolute(): + dt1 = pendulum.DateTime(2000, 1, 1) + dt2 = pendulum.DateTime(2000, 1, 31) + p = pendulum.interval(dt2, dt1, True) + + assert_datetime(p.start, 2000, 1, 1) + assert_datetime(p.end, 2000, 1, 31) + + +def test_accuracy(): + dt1 = pendulum.DateTime(2000, 11, 20) + dt2 = pendulum.DateTime(2000, 11, 25) + dt3 = pendulum.DateTime(2016, 11, 5) + p1 = pendulum.interval(dt1, dt3) + p2 = pendulum.interval(dt2, dt3) + + assert p1.years == 15 + assert p1.in_years() == 15 + assert p1.months == 11 + assert p1.in_months() == 191 + assert p1.days == 5829 + assert p1.remaining_days == 2 + assert p1.in_days() == 5829 + + assert p2.years == 15 + assert p2.in_years() == 15 + assert p2.months == 11 + assert p2.in_months() == 191 + assert p2.days == 5824 + assert p2.remaining_days == 4 + assert p2.in_days() == 5824 + + +def test_dst_transition(): + start = pendulum.datetime(2017, 3, 7, tz="America/Toronto") + end = start.add(days=6) + period = end - start + + assert period.days == 5 + assert period.seconds == 82800 + + assert period.remaining_days == 6 + assert period.hours == 0 + assert period.remaining_seconds == 0 + + assert period.in_days() == 6 + assert period.in_hours() == 5 * 24 + 23 + + +def test_timedelta_behavior(): + dt1 = pendulum.DateTime(2000, 11, 20, 1) + dt2 = pendulum.DateTime(2000, 11, 25, 2) + dt3 = pendulum.DateTime(2016, 11, 5, 3) + + p1 = pendulum.interval(dt1, dt3) + p2 = pendulum.interval(dt2, dt3) + it1 = p1.as_timedelta() + it2 = p2.as_timedelta() + + assert it1.total_seconds() == p1.total_seconds() + assert it2.total_seconds() == p2.total_seconds() + assert it1.days == p1.days + assert it2.days == p2.days + assert it1.seconds == p1.seconds + assert it2.seconds == p2.seconds + assert it1.microseconds == p1.microseconds + assert it2.microseconds == p2.microseconds + + +def test_different_timezones_same_time(): + dt1 = pendulum.datetime(2013, 3, 31, 1, 30, tz="Europe/Paris") + dt2 = pendulum.datetime(2013, 4, 1, 1, 30, tz="Europe/Paris") + period = dt2 - dt1 + + assert period.in_words() == "1 day" + assert period.in_hours() == 23 + + dt1 = pendulum.datetime(2013, 3, 31, 1, 30, tz="Europe/Paris") + dt2 = pendulum.datetime(2013, 4, 1, 1, 30, tz="America/Toronto") + period = dt2 - dt1 + + assert period.in_words() == "1 day 5 hours" + assert period.in_hours() == 29 diff --git a/tests/interval/test_hashing.py b/tests/interval/test_hashing.py new file mode 100644 index 0000000..c18502f --- /dev/null +++ b/tests/interval/test_hashing.py @@ -0,0 +1,23 @@ +from __future__ import annotations + +import pendulum + + +def test_periods_with_same_duration_and_different_dates(): + day1 = pendulum.DateTime(2018, 1, 1) + day2 = pendulum.DateTime(2018, 1, 2) + day3 = pendulum.DateTime(2018, 1, 2) + + period1 = day2 - day1 + period2 = day3 - day2 + + assert period1 != period2 + assert len({period1, period2}) == 2 + + +def test_periods_with_same_dates(): + period1 = pendulum.DateTime(2018, 1, 2) - pendulum.DateTime(2018, 1, 1) + period2 = pendulum.DateTime(2018, 1, 2) - pendulum.DateTime(2018, 1, 1) + + assert period1 == period2 + assert len({period1, period2}) == 1 diff --git a/tests/interval/test_in_words.py b/tests/interval/test_in_words.py new file mode 100644 index 0000000..410e11f --- /dev/null +++ b/tests/interval/test_in_words.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +import pendulum + + +def test_week(): + start_date = pendulum.datetime(2012, 1, 1) + period = pendulum.interval(start=start_date, end=start_date.add(weeks=1)) + assert period.in_words() == "1 week" + + +def test_week_and_day(): + start_date = pendulum.datetime(2012, 1, 1) + period = pendulum.interval(start=start_date, end=start_date.add(weeks=1, days=1)) + assert period.in_words() == "1 week 1 day" + + +def test_all(): + start_date = pendulum.datetime(2012, 1, 1) + period = pendulum.interval( + start=start_date, + end=start_date.add(years=1, months=1, days=1, seconds=1, microseconds=1), + ) + assert period.in_words() == "1 year 1 month 1 day 1 second" + + +def test_in_french(): + start_date = pendulum.datetime(2012, 1, 1) + period = pendulum.interval( + start=start_date, + end=start_date.add(years=1, months=1, days=1, seconds=1, microseconds=1), + ) + assert period.in_words(locale="fr") == "1 an 1 mois 1 jour 1 seconde" + + +def test_singular_negative_values(): + start_date = pendulum.datetime(2012, 1, 1) + period = pendulum.interval(start=start_date, end=start_date.subtract(days=1)) + assert period.in_words() == "-1 day" + + +def test_separator(): + start_date = pendulum.datetime(2012, 1, 1) + period = pendulum.interval( + start=start_date, + end=start_date.add(years=1, months=1, days=1, seconds=1, microseconds=1), + ) + assert period.in_words(separator=", ") == "1 year, 1 month, 1 day, 1 second" + + +def test_subseconds(): + start_date = pendulum.datetime(2012, 1, 1) + period = pendulum.interval( + start=start_date, end=start_date.add(microseconds=123456) + ) + assert period.in_words() == "0.12 second" + + +def test_subseconds_with_seconds(): + start_date = pendulum.datetime(2012, 1, 1) + period = pendulum.interval( + start=start_date, end=start_date.add(seconds=12, microseconds=123456) + ) + assert period.in_words() == "12 seconds" + + +def test_zero_period(): + start_date = pendulum.datetime(2012, 1, 1) + period = pendulum.interval(start=start_date, end=start_date) + assert period.in_words() == "0 microseconds" diff --git a/tests/interval/test_range.py b/tests/interval/test_range.py new file mode 100644 index 0000000..28fe1ff --- /dev/null +++ b/tests/interval/test_range.py @@ -0,0 +1,119 @@ +from __future__ import annotations + +import pendulum + +from pendulum.interval import Interval +from tests.conftest import assert_datetime + + +def test_range(): + dt1 = pendulum.datetime(2000, 1, 1, 12, 45, 37) + dt2 = pendulum.datetime(2000, 1, 31, 12, 45, 37) + + p = Interval(dt1, dt2) + r = list(p.range("days")) + + assert len(r) == 31 + assert_datetime(r[0], 2000, 1, 1, 12, 45, 37) + assert_datetime(r[-1], 2000, 1, 31, 12, 45, 37) + + +def test_range_no_overflow(): + dt1 = pendulum.datetime(2000, 1, 1, 12, 45, 37) + dt2 = pendulum.datetime(2000, 1, 31, 11, 45, 37) + + p = Interval(dt1, dt2) + r = list(p.range("days")) + + assert len(r) == 30 + assert_datetime(r[0], 2000, 1, 1, 12, 45, 37) + assert_datetime(r[-1], 2000, 1, 30, 12, 45, 37) + + +def test_range_inverted(): + dt1 = pendulum.datetime(2000, 1, 1, 12, 45, 37) + dt2 = pendulum.datetime(2000, 1, 31, 12, 45, 37) + + p = Interval(dt2, dt1) + r = list(p.range("days")) + + assert len(r) == 31 + assert_datetime(r[-1], 2000, 1, 1, 12, 45, 37) + assert_datetime(r[0], 2000, 1, 31, 12, 45, 37) + + +def test_iter(): + dt1 = pendulum.datetime(2000, 1, 1, 12, 45, 37) + dt2 = pendulum.datetime(2000, 1, 31, 12, 45, 37) + + p = Interval(dt1, dt2) + i = 0 # noqa: SIM113 (suggests use of enumerate) + for dt in p: + assert isinstance(dt, pendulum.DateTime) + i += 1 + + assert i == 31 + + +def test_contains(): + dt1 = pendulum.datetime(2000, 1, 1, 12, 45, 37) + dt2 = pendulum.datetime(2000, 1, 31, 12, 45, 37) + + p = pendulum.interval(dt1, dt2) + dt = pendulum.datetime(2000, 1, 7) + assert dt in p + + +def test_not_contains(): + dt1 = pendulum.datetime(2000, 1, 1, 12, 45, 37) + dt2 = pendulum.datetime(2000, 1, 31, 12, 45, 37) + + p = pendulum.interval(dt1, dt2) + dt = pendulum.datetime(2000, 1, 1, 11, 45, 37) + assert dt not in p + + +def test_contains_with_datetime(): + dt1 = pendulum.datetime(2000, 1, 1, 12, 45, 37) + dt2 = pendulum.datetime(2000, 1, 31, 12, 45, 37) + + p = pendulum.interval(dt1, dt2) + dt = pendulum.datetime(2000, 1, 7) + assert dt in p + + +def test_range_months_overflow(): + dt1 = pendulum.datetime(2016, 1, 30, tz="America/Sao_Paulo") + dt2 = dt1.add(months=4) + + p = pendulum.interval(dt1, dt2) + r = list(p.range("months")) + + assert_datetime(r[0], 2016, 1, 30, 0, 0, 0) + assert_datetime(r[-1], 2016, 5, 30, 0, 0, 0) + + +def test_range_with_dst(): + dt1 = pendulum.datetime(2016, 10, 14, tz="America/Sao_Paulo") + dt2 = dt1.add(weeks=1) + + p = pendulum.interval(dt1, dt2) + r = list(p.range("days")) + + assert_datetime(r[0], 2016, 10, 14, 0, 0, 0) + assert_datetime(r[2], 2016, 10, 16, 1, 0, 0) + assert_datetime(r[-1], 2016, 10, 21, 0, 0, 0) + + +def test_range_amount(): + dt1 = pendulum.datetime(2016, 10, 14, tz="America/Sao_Paulo") + dt2 = dt1.add(weeks=1) + + p = pendulum.interval(dt1, dt2) + r = list(p.range("days", 2)) + + assert len(r) == 4 + assert_datetime(r[0], 2016, 10, 14, 0, 0, 0) + assert_datetime(r[1], 2016, 10, 16, 1, 0, 0) + assert_datetime(r[2], 2016, 10, 18, 0, 0, 0) + assert_datetime(r[3], 2016, 10, 20, 0, 0, 0) diff --git a/tests/localization/__init__.py b/tests/localization/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/localization/test_cs.py b/tests/localization/test_cs.py new file mode 100644 index 0000000..71b8340 --- /dev/null +++ b/tests/localization/test_cs.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +import pendulum + +locale = "cs" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "pár vteřin zpět" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "pár vteřin zpět" + + d = pendulum.now().subtract(seconds=20) + assert d.diff_for_humans(locale=locale) == "před 20 sekundami" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "před 1 minutou" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "před 2 minutami" + + d = pendulum.now().subtract(minutes=5) + assert d.diff_for_humans(locale=locale) == "před 5 minutami" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "před 1 hodinou" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "před 2 hodinami" + + d = pendulum.now().subtract(hours=5) + assert d.diff_for_humans(locale=locale) == "před 5 hodinami" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "před 1 dnem" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "před 2 dny" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "před 1 týdnem" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "před 2 týdny" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "před 1 měsícem" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "před 2 měsíci" + + d = pendulum.now().subtract(months=5) + assert d.diff_for_humans(locale=locale) == "před 5 měsíci" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "před 1 rokem" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "před 2 lety" + + d = pendulum.now().subtract(years=5) + assert d.diff_for_humans(locale=locale) == "před 5 lety" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "za pár vteřin" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "pár vteřin po" + assert d2.diff_for_humans(d, locale=locale) == "pár vteřin zpět" + + assert d.diff_for_humans(d2, True, locale=locale) == "pár vteřin" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "pár vteřin" + + d = pendulum.now().add(seconds=20) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "20 sekund po" + assert d2.diff_for_humans(d, locale=locale) == "20 sekund zpět" + + d = pendulum.now().add(seconds=10) + d2 = pendulum.now() + assert d.diff_for_humans(d2, True, locale=locale) == "pár vteřin" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "11 sekund" + + +def test_format(): + d = pendulum.datetime(2016, 8, 29, 7, 3, 6, 123456) + assert d.format("dddd", locale=locale) == "pondělí" + assert d.format("ddd", locale=locale) == "po" + assert d.format("MMMM", locale=locale) == "srpna" + assert d.format("MMM", locale=locale) == "srp" + assert d.format("A", locale=locale) == "dop." + assert d.format("Qo", locale=locale) == "3." + assert d.format("Mo", locale=locale) == "8." + assert d.format("Do", locale=locale) == "29." + + assert d.format("LT", locale=locale) == "7:03" + assert d.format("LTS", locale=locale) == "7:03:06" + assert d.format("L", locale=locale) == "29. 8. 2016" + assert d.format("LL", locale=locale) == "29. srpna, 2016" + assert d.format("LLL", locale=locale) == "29. srpna, 2016 7:03" + assert d.format("LLLL", locale=locale) == "pondělí, 29. srpna, 2016 7:03" diff --git a/tests/localization/test_da.py b/tests/localization/test_da.py new file mode 100644 index 0000000..b08adfe --- /dev/null +++ b/tests/localization/test_da.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +import pendulum + +locale = "da" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "for 1 sekund siden" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "for 2 sekunder siden" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "for 1 minut siden" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "for 2 minutter siden" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "for 1 time siden" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "for 2 timer siden" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "for 1 dag siden" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "for 2 dage siden" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "for 1 uge siden" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "for 2 uger siden" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "for 1 måned siden" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "for 2 måneder siden" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "for 1 år siden" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "for 2 år siden" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "om 1 sekund" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1 sekund efter" + assert d2.diff_for_humans(d, locale=locale) == "1 sekund før" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 sekund" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 sekunder" diff --git a/tests/localization/test_de.py b/tests/localization/test_de.py new file mode 100644 index 0000000..9c72b79 --- /dev/null +++ b/tests/localization/test_de.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +import pendulum + +locale = "de" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "vor 1 Sekunde" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "vor 2 Sekunden" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "vor 1 Minute" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "vor 2 Minuten" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "vor 1 Stunde" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "vor 2 Stunden" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "vor 1 Tag" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "vor 2 Tagen" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "vor 1 Woche" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "vor 2 Wochen" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "vor 1 Monat" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "vor 2 Monaten" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "vor 1 Jahr" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "vor 2 Jahren" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "in 1 Sekunde" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1 Sekunde später" + assert d2.diff_for_humans(d, locale=locale) == "1 Sekunde zuvor" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 Sekunde" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 Sekunden" diff --git a/tests/localization/test_es.py b/tests/localization/test_es.py new file mode 100644 index 0000000..747ec6f --- /dev/null +++ b/tests/localization/test_es.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +import pendulum + +locale = "es" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "hace unos segundos" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "hace unos segundos" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "hace 1 minuto" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "hace 2 minutos" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "hace 1 hora" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "hace 2 horas" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "hace 1 día" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "hace 2 días" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "hace 1 semana" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "hace 2 semanas" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "hace 1 mes" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "hace 2 meses" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "hace 1 año" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "hace 2 años" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "dentro de unos segundos" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "unos segundos después" + assert d2.diff_for_humans(d, locale=locale) == "unos segundos antes" + + assert d.diff_for_humans(d2, True, locale=locale) == "unos segundos" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "unos segundos" diff --git a/tests/localization/test_fa.py b/tests/localization/test_fa.py new file mode 100644 index 0000000..39d2e4a --- /dev/null +++ b/tests/localization/test_fa.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +import pendulum + +locale = "fa" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "1 ثانیه پیش" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "2 ثانیه پیش" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "1 دقیقه پیش" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2 دقیقه پیش" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "1 ساعت پیش" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2 ساعت پیش" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "1 روز پیش" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2 روز پیش" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "1 هفته پیش" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2 هفته پیش" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "1 ماه پیش" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2 ماه پیش" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "1 سال پیش" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2 سال پیش" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "1 ثانیه بعد" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1 ثانیه پس از" + assert d2.diff_for_humans(d, locale=locale) == "1 ثانیه پیش از" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 ثانیه" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 ثانیه" diff --git a/tests/localization/test_fo.py b/tests/localization/test_fo.py new file mode 100644 index 0000000..f451553 --- /dev/null +++ b/tests/localization/test_fo.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +import pendulum + +locale = "fo" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "1 sekund síðan" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "2 sekund síðan" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "1 minutt síðan" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2 minuttir síðan" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "1 tími síðan" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2 tímar síðan" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "1 dagur síðan" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2 dagar síðan" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "1 vika síðan" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2 vikur síðan" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "1 mánað síðan" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2 mánaðir síðan" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "1 ár síðan" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2 ár síðan" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "um 1 sekund" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1 sekund aftaná" + assert d2.diff_for_humans(d, locale=locale) == "1 sekund áðrenn" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 sekund" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 sekundir" diff --git a/tests/localization/test_fr.py b/tests/localization/test_fr.py new file mode 100644 index 0000000..1cfef5b --- /dev/null +++ b/tests/localization/test_fr.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +import pendulum + +locale = "fr" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "il y a quelques secondes" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "il y a quelques secondes" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "il y a 1 minute" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "il y a 2 minutes" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "il y a 1 heure" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "il y a 2 heures" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "il y a 1 jour" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "il y a 2 jours" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "il y a 1 semaine" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "il y a 2 semaines" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "il y a 1 mois" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "il y a 2 mois" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "il y a 1 an" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "il y a 2 ans" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "dans quelques secondes" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "quelques secondes après" + assert d2.diff_for_humans(d, locale=locale) == "quelques secondes avant" + + assert d.diff_for_humans(d2, True, locale=locale) == "quelques secondes" + assert ( + d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "quelques secondes" + ) + + +def test_format(): + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456) + assert d.format("dddd", locale=locale) == "dimanche" + assert d.format("ddd", locale=locale) == "dim." + assert d.format("MMMM", locale=locale) == "août" + assert d.format("MMM", locale=locale) == "août" + assert d.format("A", locale=locale) == "AM" + assert d.format("Do", locale=locale) == "28e" + + assert d.format("LT", locale=locale) == "07:03" + assert d.format("LTS", locale=locale) == "07:03:06" + assert d.format("L", locale=locale) == "28/08/2016" + assert d.format("LL", locale=locale) == "28 août 2016" + assert d.format("LLL", locale=locale) == "28 août 2016 07:03" + assert d.format("LLLL", locale=locale) == "dimanche 28 août 2016 07:03" diff --git a/tests/localization/test_he.py b/tests/localization/test_he.py new file mode 100644 index 0000000..6186ef2 --- /dev/null +++ b/tests/localization/test_he.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +import pendulum + +locale = "he" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "לפני כמה שניות" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "לפני כמה שניות" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "לפני דקה" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "לפני שתי דקות" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "לפני שעה" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "לפני שעתיים" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "לפני יום 1" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "לפני יומיים" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "לפני שבוע" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "לפני שבועיים" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "לפני חודש" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "לפני חודשיים" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "לפני שנה" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "לפני שנתיים" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "תוך כמה שניות" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "בעוד כמה שניות" + assert d2.diff_for_humans(d, locale=locale) == "כמה שניות קודם" + + assert d.diff_for_humans(d2, True, locale=locale) == "כמה שניות" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "כמה שניות" diff --git a/tests/localization/test_id.py b/tests/localization/test_id.py new file mode 100644 index 0000000..3dd316c --- /dev/null +++ b/tests/localization/test_id.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +import pendulum + +locale = "id" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "beberapa detik yang lalu" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "beberapa detik yang lalu" + + d = pendulum.now().subtract(seconds=21) + assert d.diff_for_humans(locale=locale) == "21 detik yang lalu" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "1 menit yang lalu" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2 menit yang lalu" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "1 jam yang lalu" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2 jam yang lalu" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "1 hari yang lalu" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2 hari yang lalu" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "1 minggu yang lalu" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2 minggu yang lalu" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "1 bulan yang lalu" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2 bulan yang lalu" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "1 tahun yang lalu" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2 tahun yang lalu" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "dalam beberapa detik" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "beberapa detik kemudian" + assert d2.diff_for_humans(d, locale=locale) == "beberapa detik yang lalu" + + assert d.diff_for_humans(d2, True, locale=locale) == "beberapa detik" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "beberapa detik" diff --git a/tests/localization/test_it.py b/tests/localization/test_it.py new file mode 100644 index 0000000..1918a2b --- /dev/null +++ b/tests/localization/test_it.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +import pendulum + +locale = "it" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "alcuni secondi fa" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "alcuni secondi fa" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "1 minuto fa" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2 minuti fa" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "1 ora fa" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2 ore fa" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "1 giorno fa" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2 giorni fa" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "1 settimana fa" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2 settimane fa" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "1 mese fa" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2 mesi fa" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "1 anno fa" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2 anni fa" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "in alcuni secondi" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "alcuni secondi dopo" + assert d2.diff_for_humans(d, locale=locale) == "alcuni secondi prima" + + assert d.diff_for_humans(d2, True, locale=locale) == "alcuni secondi" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "alcuni secondi" + + +def test_format(): + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456) + assert d.format("dddd", locale=locale) == "domenica" + assert d.format("ddd", locale=locale) == "dom" + assert d.format("MMMM", locale=locale) == "agosto" + assert d.format("MMM", locale=locale) == "ago" + assert d.format("A", locale=locale) == "AM" + + assert d.format("LT", locale=locale) == "7:03" + assert d.format("LTS", locale=locale) == "7:03:06" + assert d.format("L", locale=locale) == "28/08/2016" + assert d.format("LL", locale=locale) == "28 agosto 2016" + assert d.format("LLL", locale=locale) == "28 agosto 2016 alle 7:03" + assert d.format("LLLL", locale=locale) == "domenica, 28 agosto 2016 alle 7:03" + + assert d.format("Do", locale=locale) == "28°" + d = pendulum.datetime(2019, 1, 1, 7, 3, 6, 123456) + assert d.format("Do", locale=locale) == "1°" diff --git a/tests/localization/test_ja.py b/tests/localization/test_ja.py new file mode 100644 index 0000000..82457fd --- /dev/null +++ b/tests/localization/test_ja.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +import pendulum + +locale = "ja" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "数秒 前に" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "数秒 前に" + + d = pendulum.now().subtract(seconds=21) + assert d.diff_for_humans(locale=locale) == "21 秒前" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "1 分前" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2 分前" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "1 時間前" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2 時間前" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "1 日前" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2 日前" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "1 週間前" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2 週間前" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "1 か月前" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2 か月前" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "1 年前" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2 年前" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "今から 数秒" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "数秒 後" + assert d2.diff_for_humans(d, locale=locale) == "数秒 前" + + assert d.diff_for_humans(d2, True, locale=locale) == "数秒" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "数秒" diff --git a/tests/localization/test_ko.py b/tests/localization/test_ko.py new file mode 100644 index 0000000..e33ca25 --- /dev/null +++ b/tests/localization/test_ko.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +import pendulum + +locale = "ko" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "1초 전" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "2초 전" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "1분 전" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2분 전" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "1시간 전" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2시간 전" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "1일 전" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2일 전" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "1주 전" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2주 전" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "1개월 전" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2개월 전" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "1년 전" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2년 전" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "1초 후" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1초 뒤" + assert d2.diff_for_humans(d, locale=locale) == "1초 앞" + + assert d.diff_for_humans(d2, True, locale=locale) == "1초" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2초" diff --git a/tests/localization/test_lt.py b/tests/localization/test_lt.py new file mode 100644 index 0000000..71de1ac --- /dev/null +++ b/tests/localization/test_lt.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +import pendulum + +locale = "lt" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "prieš 1 sekundę" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "prieš 2 sekundes" + + d = pendulum.now().subtract(seconds=21) + assert d.diff_for_humans(locale=locale) == "prieš 21 sekundę" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "prieš 1 minutę" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "prieš 2 minutes" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "prieš 1 valandą" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "prieš 2 valandas" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "prieš 1 dieną" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "prieš 2 dienas" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "prieš 1 savaitę" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "prieš 2 savaites" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "prieš 1 mėnesį" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "prieš 2 mėnesius" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "prieš 1 metus" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "prieš 2 metus" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "po 1 sekundės" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "po 1 sekundės" + assert d2.diff_for_humans(d, locale=locale) == "1 sekundę nuo dabar" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 sekundė" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 sekundės" diff --git a/tests/localization/test_nb.py b/tests/localization/test_nb.py new file mode 100644 index 0000000..3f696e5 --- /dev/null +++ b/tests/localization/test_nb.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +import pendulum + +locale = "nb" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "for 1 sekund siden" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "for 2 sekunder siden" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "for 1 minutt siden" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "for 2 minutter siden" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "for 1 time siden" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "for 2 timer siden" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "for 1 dag siden" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "for 2 dager siden" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "for 1 uke siden" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "for 2 uker siden" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "for 1 måned siden" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "for 2 måneder siden" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "for 1 år siden" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "for 2 år siden" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "om 1 sekund" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1 sekund etter" + assert d2.diff_for_humans(d, locale=locale) == "1 sekund før" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 sekund" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 sekunder" + + +def test_format(): + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456) + assert d.format("dddd", locale=locale) == "søndag" + assert d.format("ddd", locale=locale) == "søn." + assert d.format("MMMM", locale=locale) == "august" + assert d.format("MMM", locale=locale) == "aug." + assert d.format("A", locale=locale) == "a.m." + assert d.format("Qo", locale=locale) == "3." + assert d.format("Mo", locale=locale) == "8." + assert d.format("Do", locale=locale) == "28." + + assert d.format("LT", locale=locale) == "07:03" + assert d.format("LTS", locale=locale) == "07:03:06" + assert d.format("L", locale=locale) == "28.08.2016" + assert d.format("LL", locale=locale) == "28. august 2016" + assert d.format("LLL", locale=locale) == "28. august 2016 07:03" + assert d.format("LLLL", locale=locale) == "søndag 28. august 2016 07:03" diff --git a/tests/localization/test_nl.py b/tests/localization/test_nl.py new file mode 100644 index 0000000..68227ec --- /dev/null +++ b/tests/localization/test_nl.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +import pendulum + +locale = "nl" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "enkele seconden geleden" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "enkele seconden geleden" + + d = pendulum.now().subtract(seconds=22) + assert d.diff_for_humans(locale=locale) == "22 seconden geleden" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "1 minuut geleden" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2 minuten geleden" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "1 uur geleden" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2 uur geleden" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "1 dag geleden" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2 dagen geleden" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "1 week geleden" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2 weken geleden" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "1 maand geleden" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2 maanden geleden" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "1 jaar geleden" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2 jaar geleden" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "over enkele seconden" + + d = pendulum.now().add(weeks=1) + assert d.diff_for_humans(locale=locale) == "over 1 week" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "enkele seconden later" + assert d2.diff_for_humans(d, locale=locale) == "enkele seconden eerder" + + assert d.diff_for_humans(d2, True, locale=locale) == "enkele seconden" + assert ( + d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "enkele seconden" + ) + + +def test_format(): + d = pendulum.datetime(2016, 8, 28, 7, 3, 6, 123456) + assert d.format("dddd", locale=locale) == "zondag" + assert d.format("ddd", locale=locale) == "zo" + assert d.format("MMMM", locale=locale) == "augustus" + assert d.format("MMM", locale=locale) == "aug." + assert d.format("A", locale=locale) == "a.m." + assert d.format("Do", locale=locale) == "28e" diff --git a/tests/localization/test_nn.py b/tests/localization/test_nn.py new file mode 100644 index 0000000..d4b8099 --- /dev/null +++ b/tests/localization/test_nn.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +import pendulum + +locale = "nn" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "for 1 sekund sidan" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "for 2 sekund sidan" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "for 1 minutt sidan" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "for 2 minutt sidan" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "for 1 time sidan" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "for 2 timar sidan" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "for 1 dag sidan" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "for 2 dagar sidan" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "for 1 veke sidan" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "for 2 veker sidan" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "for 1 månad sidan" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "for 2 månadar sidan" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "for 1 år sidan" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "for 2 år sidan" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "om 1 sekund" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1 sekund etter" + assert d2.diff_for_humans(d, locale=locale) == "1 sekund før" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 sekund" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 sekund" + + +def test_format(): + d = pendulum.datetime(2016, 8, 29, 7, 3, 6, 123456) + assert d.format("dddd", locale=locale) == "måndag" + assert d.format("ddd", locale=locale) == "mån." + assert d.format("MMMM", locale=locale) == "august" + assert d.format("MMM", locale=locale) == "aug." + assert d.format("A", locale=locale) == "formiddag" + assert d.format("Qo", locale=locale) == "3." + assert d.format("Mo", locale=locale) == "8." + assert d.format("Do", locale=locale) == "29." + + assert d.format("LT", locale=locale) == "07:03" + assert d.format("LTS", locale=locale) == "07:03:06" + assert d.format("L", locale=locale) == "29.08.2016" + assert d.format("LL", locale=locale) == "29. august 2016" + assert d.format("LLL", locale=locale) == "29. august 2016 07:03" + assert d.format("LLLL", locale=locale) == "måndag 29. august 2016 07:03" diff --git a/tests/localization/test_pl.py b/tests/localization/test_pl.py new file mode 100644 index 0000000..2b6e707 --- /dev/null +++ b/tests/localization/test_pl.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +import pendulum + +locale = "pl" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "kilka sekund temu" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "kilka sekund temu" + + d = pendulum.now().subtract(seconds=20) + assert d.diff_for_humans(locale=locale) == "20 sekund temu" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "1 minutę temu" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2 minuty temu" + + d = pendulum.now().subtract(minutes=5) + assert d.diff_for_humans(locale=locale) == "5 minut temu" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "1 godzinę temu" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2 godziny temu" + + d = pendulum.now().subtract(hours=5) + assert d.diff_for_humans(locale=locale) == "5 godzin temu" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "1 dzień temu" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2 dni temu" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "1 tydzień temu" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2 tygodnie temu" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "1 miesiąc temu" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2 miesiące temu" + + d = pendulum.now().subtract(months=5) + assert d.diff_for_humans(locale=locale) == "5 miesięcy temu" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "1 rok temu" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2 lata temu" + + d = pendulum.now().subtract(years=5) + assert d.diff_for_humans(locale=locale) == "5 lat temu" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "za kilka sekund" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "kilka sekund po" + assert d2.diff_for_humans(d, locale=locale) == "kilka sekund przed" + + assert d.diff_for_humans(d2, True, locale=locale) == "kilka sekund" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "kilka sekund" + + d = pendulum.now().add(seconds=20) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "20 sekund po" + assert d2.diff_for_humans(d, locale=locale) == "20 sekund przed" + + d = pendulum.now().add(seconds=10) + d2 = pendulum.now() + assert d.diff_for_humans(d2, True, locale=locale) == "kilka sekund" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "11 sekund" + + +def test_format(): + d = pendulum.datetime(2016, 8, 29, 7, 3, 6, 123456) + assert d.format("dddd", locale=locale) == "poniedziałek" + assert d.format("ddd", locale=locale) == "pon." + assert d.format("MMMM", locale=locale) == "sierpnia" + assert d.format("MMM", locale=locale) == "sie" + assert d.format("A", locale=locale) == "AM" + assert d.format("Qo", locale=locale) == "3" + assert d.format("Mo", locale=locale) == "8" + assert d.format("Do", locale=locale) == "29" + + assert d.format("LT", locale=locale) == "07:03" + assert d.format("LTS", locale=locale) == "07:03:06" + assert d.format("L", locale=locale) == "29.08.2016" + assert d.format("LL", locale=locale) == "29 sierpnia 2016" + assert d.format("LLL", locale=locale) == "29 sierpnia 2016 07:03" + assert d.format("LLLL", locale=locale) == "poniedziałek, 29 sierpnia 2016 07:03" diff --git a/tests/localization/test_ru.py b/tests/localization/test_ru.py new file mode 100644 index 0000000..be0e645 --- /dev/null +++ b/tests/localization/test_ru.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import pendulum + +locale = "ru" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "1 секунду назад" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "2 секунды назад" + + d = pendulum.now().subtract(seconds=5) + assert d.diff_for_humans(locale=locale) == "5 секунд назад" + + d = pendulum.now().subtract(seconds=21) + assert d.diff_for_humans(locale=locale) == "21 секунду назад" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "1 минуту назад" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "2 минуты назад" + + d = pendulum.now().subtract(minutes=5) + assert d.diff_for_humans(locale=locale) == "5 минут назад" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "1 час назад" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "2 часа назад" + + d = pendulum.now().subtract(hours=5) + assert d.diff_for_humans(locale=locale) == "5 часов назад" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "1 день назад" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "2 дня назад" + + d = pendulum.now().subtract(days=5) + assert d.diff_for_humans(locale=locale) == "5 дней назад" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "1 неделю назад" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "2 недели назад" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "1 месяц назад" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "2 месяца назад" + + d = pendulum.now().subtract(months=5) + assert d.diff_for_humans(locale=locale) == "5 месяцев назад" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "1 год назад" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "2 года назад" + + d = pendulum.now().subtract(years=5) + assert d.diff_for_humans(locale=locale) == "5 лет назад" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "через 1 секунду" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1 секунда после" + assert d2.diff_for_humans(d, locale=locale) == "1 секунда до" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 секунда" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 секунды" diff --git a/tests/localization/test_sk.py b/tests/localization/test_sk.py new file mode 100644 index 0000000..5553e7f --- /dev/null +++ b/tests/localization/test_sk.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +import pendulum + +locale = "sk" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "pred 1 sekundou" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "o 1 sekundu" + + d = pendulum.now().add(seconds=2) + assert d.diff_for_humans(locale=locale) == "o 2 sekundy" + + d = pendulum.now().add(seconds=5) + assert d.diff_for_humans(locale=locale) == "o 5 sekúnd" + + d = pendulum.now().subtract(seconds=20) + assert d.diff_for_humans(locale=locale) == "pred 20 sekundami" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "pred 1 minútou" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "pred 2 minútami" + + d = pendulum.now().add(minutes=5) + assert d.diff_for_humans(locale=locale) == "o 5 minút" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "pred 1 hodinou" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "pred 2 hodinami" + + d = pendulum.now().subtract(hours=5) + assert d.diff_for_humans(locale=locale) == "pred 5 hodinami" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "pred 1 dňom" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "pred 2 dňami" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "pred 1 týždňom" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "pred 2 týždňami" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "pred 1 mesiacom" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "pred 2 mesiacmi" + + d = pendulum.now().subtract(months=5) + assert d.diff_for_humans(locale=locale) == "pred 5 mesiacmi" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "pred 1 rokom" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "pred 2 rokmi" + + d = pendulum.now().subtract(years=5) + assert d.diff_for_humans(locale=locale) == "pred 5 rokmi" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1 sekunda po" + assert d2.diff_for_humans(d, locale=locale) == "1 sekunda pred" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 sekunda" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 sekundy" + + d = pendulum.now().add(seconds=20) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "20 sekúnd po" + assert d2.diff_for_humans(d, locale=locale) == "20 sekúnd pred" + + d = pendulum.now().add(seconds=10) + d2 = pendulum.now() + assert d.diff_for_humans(d2, True, locale=locale) == "10 sekúnd" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "11 sekúnd" + + +def test_format(): + d = pendulum.datetime(2016, 8, 29, 7, 3, 6, 123456) + assert d.format("dddd", locale=locale) == "pondelok" + assert d.format("ddd", locale=locale) == "po" + assert d.format("MMMM", locale=locale) == "augusta" + assert d.format("MMM", locale=locale) == "aug" + assert d.format("A", locale=locale) == "AM" + assert d.format("Qo", locale=locale) == "3" + assert d.format("Mo", locale=locale) == "8" + assert d.format("Do", locale=locale) == "29" + + assert d.format("LT", locale=locale) == "07:03" + assert d.format("LTS", locale=locale) == "07:03:06" + assert d.format("L", locale=locale) == "29.08.2016" + assert d.format("LL", locale=locale) == "29. augusta 2016" + assert d.format("LLL", locale=locale) == "29. augusta 2016 07:03" + assert d.format("LLLL", locale=locale) == "pondelok, 29. augusta 2016 07:03" diff --git a/tests/localization/test_sv.py b/tests/localization/test_sv.py new file mode 100644 index 0000000..e0e4e65 --- /dev/null +++ b/tests/localization/test_sv.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import pendulum + +locale = "sv" + + +def test_diff_for_humans(): + with pendulum.travel_to(pendulum.datetime(2016, 8, 29), freeze=True): + diff_for_humans() + + +def diff_for_humans(): + d = pendulum.now().subtract(seconds=1) + assert d.diff_for_humans(locale=locale) == "för 1 sekund sedan" + + d = pendulum.now().subtract(seconds=2) + assert d.diff_for_humans(locale=locale) == "för 2 sekunder sedan" + + d = pendulum.now().subtract(seconds=5) + assert d.diff_for_humans(locale=locale) == "för 5 sekunder sedan" + + d = pendulum.now().subtract(seconds=21) + assert d.diff_for_humans(locale=locale) == "för 21 sekunder sedan" + + d = pendulum.now().subtract(minutes=1) + assert d.diff_for_humans(locale=locale) == "för 1 minut sedan" + + d = pendulum.now().subtract(minutes=2) + assert d.diff_for_humans(locale=locale) == "för 2 minuter sedan" + + d = pendulum.now().subtract(minutes=5) + assert d.diff_for_humans(locale=locale) == "för 5 minuter sedan" + + d = pendulum.now().subtract(hours=1) + assert d.diff_for_humans(locale=locale) == "för 1 timme sedan" + + d = pendulum.now().subtract(hours=2) + assert d.diff_for_humans(locale=locale) == "för 2 timmar sedan" + + d = pendulum.now().subtract(hours=5) + assert d.diff_for_humans(locale=locale) == "för 5 timmar sedan" + + d = pendulum.now().subtract(days=1) + assert d.diff_for_humans(locale=locale) == "för 1 dag sedan" + + d = pendulum.now().subtract(days=2) + assert d.diff_for_humans(locale=locale) == "för 2 dagar sedan" + + d = pendulum.now().subtract(days=5) + assert d.diff_for_humans(locale=locale) == "för 5 dagar sedan" + + d = pendulum.now().subtract(weeks=1) + assert d.diff_for_humans(locale=locale) == "för 1 vecka sedan" + + d = pendulum.now().subtract(weeks=2) + assert d.diff_for_humans(locale=locale) == "för 2 veckor sedan" + + d = pendulum.now().subtract(months=1) + assert d.diff_for_humans(locale=locale) == "för 1 månad sedan" + + d = pendulum.now().subtract(months=2) + assert d.diff_for_humans(locale=locale) == "för 2 månader sedan" + + d = pendulum.now().subtract(months=5) + assert d.diff_for_humans(locale=locale) == "för 5 månader sedan" + + d = pendulum.now().subtract(years=1) + assert d.diff_for_humans(locale=locale) == "för 1 år sedan" + + d = pendulum.now().subtract(years=2) + assert d.diff_for_humans(locale=locale) == "för 2 år sedan" + + d = pendulum.now().subtract(years=5) + assert d.diff_for_humans(locale=locale) == "för 5 år sedan" + + d = pendulum.now().add(seconds=1) + assert d.diff_for_humans(locale=locale) == "om 1 sekund" + + d = pendulum.now().add(seconds=1) + d2 = pendulum.now() + assert d.diff_for_humans(d2, locale=locale) == "1 sekund efter" + assert d2.diff_for_humans(d, locale=locale) == "1 sekund innan" + + assert d.diff_for_humans(d2, True, locale=locale) == "1 sekund" + assert d2.diff_for_humans(d.add(seconds=1), True, locale=locale) == "2 sekunder" diff --git a/tests/parsing/__init__.py b/tests/parsing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/parsing/test_parse_iso8601.py b/tests/parsing/test_parse_iso8601.py new file mode 100644 index 0000000..0047791 --- /dev/null +++ b/tests/parsing/test_parse_iso8601.py @@ -0,0 +1,465 @@ +from __future__ import annotations + +from datetime import date +from datetime import datetime +from datetime import time + +import pytest + +from pendulum.parsing import parse_iso8601 + +try: + from pendulum.parsing._extension import TZFixedOffset as FixedTimezone +except ImportError: + from pendulum.tz.timezone import FixedTimezone + + +def test_parse_iso8601(): + # Date + assert date(2016, 1, 1) == parse_iso8601("2016") + assert date(2016, 10, 1) == parse_iso8601("2016-10") + assert date(2016, 10, 6) == parse_iso8601("2016-10-06") + assert date(2016, 10, 6) == parse_iso8601("20161006") + + # Time + assert time(20, 16, 10, 0) == parse_iso8601("201610") + + # Datetime + assert datetime(2016, 10, 6, 12, 34, 56, 123456) == parse_iso8601( + "2016-10-06T12:34:56.123456" + ) + assert datetime(2016, 10, 6, 12, 34, 56, 123000) == parse_iso8601( + "2016-10-06T12:34:56.123" + ) + assert datetime(2016, 10, 6, 12, 34, 56, 123) == parse_iso8601( + "2016-10-06T12:34:56.000123" + ) + assert datetime(2016, 10, 6, 12, 0, 0, 0) == parse_iso8601("2016-10-06T12") + assert datetime(2016, 10, 6, 12, 34, 56, 0) == parse_iso8601("2016-10-06T123456") + assert datetime(2016, 10, 6, 12, 34, 56, 123456) == parse_iso8601( + "2016-10-06T123456.123456" + ) + assert datetime(2016, 10, 6, 12, 34, 56, 123456) == parse_iso8601( + "20161006T123456.123456" + ) + assert datetime(2016, 10, 6, 12, 34, 56, 123456) == parse_iso8601( + "20161006 123456.123456" + ) + + # Datetime with offset + assert datetime( + 2016, 10, 6, 12, 34, 56, 123456, FixedTimezone(19800) + ) == parse_iso8601("2016-10-06T12:34:56.123456+05:30") + assert datetime( + 2016, 10, 6, 12, 34, 56, 123456, FixedTimezone(19800) + ) == parse_iso8601("2016-10-06T12:34:56.123456+0530") + assert datetime( + 2016, 10, 6, 12, 34, 56, 123456, FixedTimezone(-19800) + ) == parse_iso8601("2016-10-06T12:34:56.123456-05:30") + assert datetime( + 2016, 10, 6, 12, 34, 56, 123456, FixedTimezone(-19800) + ) == parse_iso8601("2016-10-06T12:34:56.123456-0530") + assert datetime( + 2016, 10, 6, 12, 34, 56, 123456, FixedTimezone(18000) + ) == parse_iso8601("2016-10-06T12:34:56.123456+05") + assert datetime( + 2016, 10, 6, 12, 34, 56, 123456, FixedTimezone(-18000) + ) == parse_iso8601("2016-10-06T12:34:56.123456-05") + assert datetime( + 2016, 10, 6, 12, 34, 56, 123456, FixedTimezone(-18000) + ) == parse_iso8601("20161006T123456,123456-05") + assert datetime( + 2016, 10, 6, 12, 34, 56, 123456, FixedTimezone(+19800) + ) == parse_iso8601("2016-10-06T12:34:56.123456789+05:30") + + # Ordinal date + assert date(2012, 1, 7) == parse_iso8601("2012-007") + assert date(2012, 1, 7) == parse_iso8601("2012007") + assert date(2017, 3, 20) == parse_iso8601("2017-079") + + # Week date + assert date(2012, 1, 30) == parse_iso8601("2012-W05") + assert date(2008, 9, 27) == parse_iso8601("2008-W39-6") + assert date(2010, 1, 3) == parse_iso8601("2009-W53-7") + assert date(2008, 12, 29) == parse_iso8601("2009-W01-1") + + # Week date wth time + assert datetime(2008, 9, 27, 9, 0, 0, 0) == parse_iso8601("2008-W39-6T09") + + +def test_parse_ios8601_invalid(): + # Invalid month + with pytest.raises(ValueError): + parse_iso8601("20161306T123456") + + # Invalid day + with pytest.raises(ValueError): + parse_iso8601("20161033T123456") + + # Invalid day for month + with pytest.raises(ValueError): + parse_iso8601("20161131T123456") + + # Invalid hour + with pytest.raises(ValueError): + parse_iso8601("20161006T243456") + + # Invalid minute + with pytest.raises(ValueError): + parse_iso8601("20161006T126056") + + # Invalid second + with pytest.raises(ValueError): + parse_iso8601("20161006T123460") + + # Extraneous separator + with pytest.raises(ValueError): + parse_iso8601("20140203 04:05:.123456") + with pytest.raises(ValueError): + parse_iso8601("2009-05-19 14:") + + # Invalid ordinal + with pytest.raises(ValueError): + parse_iso8601("2009367") + with pytest.raises(ValueError): + parse_iso8601("2009-367") + with pytest.raises(ValueError): + parse_iso8601("2015-366") + with pytest.raises(ValueError): + parse_iso8601("2015-000") + + # Invalid date + with pytest.raises(ValueError): + parse_iso8601("2009-") + + # Invalid time + with pytest.raises(ValueError): + parse_iso8601("2009-05-19T14:3924") + with pytest.raises(ValueError): + parse_iso8601("2010-02-18T16.5:23.35:48") + with pytest.raises(ValueError): + parse_iso8601("2010-02-18T16:23.35:48.45") + with pytest.raises(ValueError): + parse_iso8601("2010-02-18T16:23.33.600") + + # Invalid offset + with pytest.raises(ValueError): + parse_iso8601("2009-05-19 14:39:22+063") + with pytest.raises(ValueError): + parse_iso8601("2009-05-19 14:39:22+06a00") + with pytest.raises(ValueError): + parse_iso8601("2009-05-19 14:39:22+0:6:00") + + # Missing time separator + with pytest.raises(ValueError): + parse_iso8601("2009-05-1914:39") + + # Invalid week date + with pytest.raises(ValueError): + parse_iso8601("2012-W63") + with pytest.raises(ValueError): + parse_iso8601("2012-W12-9") + with pytest.raises(ValueError): + parse_iso8601("2012W12-3") # Missing separator + with pytest.raises(ValueError): + parse_iso8601("2012-W123") # Missing separator + + +def test_parse_ios8601_duration(): + text = "P2Y3M4DT5H6M7S" + parsed = parse_iso8601(text) + + assert parsed.years == 2 + assert parsed.months == 3 + assert parsed.weeks == 0 + assert parsed.remaining_days == 4 + assert parsed.hours == 5 + assert parsed.minutes == 6 + assert parsed.remaining_seconds == 7 + assert parsed.microseconds == 0 + + text = "P1Y2M3DT4H5M6.5S" + parsed = parse_iso8601(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 4 + assert parsed.minutes == 5 + assert parsed.remaining_seconds == 6 + assert parsed.microseconds == 500000 + + text = "P1Y2M3DT4H5M6,5S" + parsed = parse_iso8601(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 4 + assert parsed.minutes == 5 + assert parsed.remaining_seconds == 6 + assert parsed.microseconds == 500000 + + text = "P1Y2M3D" + parsed = parse_iso8601(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1Y2M3.5D" + parsed = parse_iso8601(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1Y2M3,5D" + parsed = parse_iso8601(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "PT4H54M6.5S" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 4 + assert parsed.minutes == 54 + assert parsed.remaining_seconds == 6 + assert parsed.microseconds == 500000 + + text = "PT4H54M6,5S" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 4 + assert parsed.minutes == 54 + assert parsed.remaining_seconds == 6 + assert parsed.microseconds == 500000 + + text = "P1Y" + parsed = parse_iso8601(text) + + assert parsed.years == 1 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1.5Y" + with pytest.raises(ValueError): + parse_iso8601(text) + + text = "P1,5Y" + with pytest.raises(ValueError): + parse_iso8601(text) + + text = "P1M" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 1 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1.5M" + with pytest.raises(ValueError): + parse_iso8601(text) + + text = "P1,5M" + with pytest.raises(ValueError): + parse_iso8601(text) + + text = "P1W" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 1 + assert parsed.remaining_days == 0 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1.5W" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 1 + assert parsed.remaining_days == 3 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1,5W" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 1 + assert parsed.remaining_days == 3 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1D" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 1 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1.5D" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 1 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1,5D" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 1 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "PT1H" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 1 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "PT1.5H" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 1 + assert parsed.minutes == 30 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "PT1,5H" + parsed = parse_iso8601(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 1 + assert parsed.minutes == 30 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + # Double digit with 0 + text = "P2Y30M4DT5H6M7S" + parsed = parse_iso8601(text) + + assert parsed.years == 2 + assert parsed.months == 30 + assert parsed.weeks == 0 + assert parsed.remaining_days == 4 + assert parsed.hours == 5 + assert parsed.minutes == 6 + assert parsed.remaining_seconds == 7 + assert parsed.microseconds == 0 + + # No P operator + with pytest.raises(ValueError): + parse_iso8601("2Y3M4DT5H6M7S") + + # Week and other units combined + with pytest.raises(ValueError): + parse_iso8601("P1Y2W") + + # Invalid units order + with pytest.raises(ValueError): + parse_iso8601("P1S") + + with pytest.raises(ValueError): + parse_iso8601("P1D1S") + + with pytest.raises(ValueError): + parse_iso8601("1Y2M3D1SPT1M") + + with pytest.raises(ValueError): + parse_iso8601("P1Y2M3D2MT1S") + + with pytest.raises(ValueError): + parse_iso8601("P2M3D1ST1Y1M") + + with pytest.raises(ValueError): + parse_iso8601("P1Y2M2MT3D1S") + + with pytest.raises(ValueError): + parse_iso8601("P1D1Y1M") + + with pytest.raises(ValueError): + parse_iso8601("PT1S1H") + + # Invalid + with pytest.raises(ValueError): + parse_iso8601("P1Dasdfasdf") + + # Invalid fractional + with pytest.raises(ValueError): + parse_iso8601("P2Y3M4DT5.5H6M7S") diff --git a/tests/parsing/test_parsing.py b/tests/parsing/test_parsing.py new file mode 100644 index 0000000..35dcf86 --- /dev/null +++ b/tests/parsing/test_parsing.py @@ -0,0 +1,687 @@ +from __future__ import annotations + +import datetime + +import pytest + +import pendulum + +from pendulum.parsing import ParserError +from pendulum.parsing import parse + + +def test_y(): + text = "2016" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 1 + assert parsed.day == 1 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_ym(): + text = "2016-10" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 1 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_ymd(): + text = "2016-10-06" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 6 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_ymd_one_character(): + text = "2016-2-6" + + parsed = parse(text, strict=False) + + assert parsed.year == 2016 + assert parsed.month == 2 + assert parsed.day == 6 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_ymd_hms(): + text = "2016-10-06 12:34:56" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 6 + assert parsed.hour == 12 + assert parsed.minute == 34 + assert parsed.second == 56 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2016-10-06 12:34:56.123456" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 6 + assert parsed.hour == 12 + assert parsed.minute == 34 + assert parsed.second == 56 + assert parsed.microsecond == 123456 + assert parsed.tzinfo is None + + +def test_rfc_3339(): + text = "2016-10-06T12:34:56+05:30" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 6 + assert parsed.hour == 12 + assert parsed.minute == 34 + assert parsed.second == 56 + assert parsed.microsecond == 0 + assert parsed.utcoffset().total_seconds() == 19800 + + +def test_rfc_3339_extended(): + text = "2016-10-06T12:34:56.123456+05:30" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 6 + assert parsed.hour == 12 + assert parsed.minute == 34 + assert parsed.second == 56 + assert parsed.microsecond == 123456 + assert parsed.utcoffset().total_seconds() == 19800 + + text = "2016-10-06T12:34:56.000123+05:30" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 6 + assert parsed.hour == 12 + assert parsed.minute == 34 + assert parsed.second == 56 + assert parsed.microsecond == 123 + assert parsed.utcoffset().total_seconds() == 19800 + + +def test_rfc_3339_extended_nanoseconds(): + text = "2016-10-06T12:34:56.123456789+05:30" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 6 + assert parsed.hour == 12 + assert parsed.minute == 34 + assert parsed.second == 56 + assert parsed.microsecond == 123456 + assert parsed.utcoffset().total_seconds() == 19800 + + +def test_iso_8601_date(): + text = "2012" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 1 + assert parsed.day == 1 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2012-05-03" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 5 + assert parsed.day == 3 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "20120503" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 5 + assert parsed.day == 3 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2012-05" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 5 + assert parsed.day == 1 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_iso8601_datetime(): + text = "2016-10-01T14" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 1 + assert parsed.hour == 14 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2016-10-01T14:30" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 1 + assert parsed.hour == 14 + assert parsed.minute == 30 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "20161001T14" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 1 + assert parsed.hour == 14 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "20161001T1430" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 1 + assert parsed.hour == 14 + assert parsed.minute == 30 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "20161001T1430+0530" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 1 + assert parsed.hour == 14 + assert parsed.minute == 30 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.utcoffset().total_seconds() == 19800 + + text = "20161001T1430,4+0530" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 10 + assert parsed.day == 1 + assert parsed.hour == 14 + assert parsed.minute == 30 + assert parsed.second == 0 + assert parsed.microsecond == 400000 + assert parsed.utcoffset().total_seconds() == 19800 + + text = "2008-09-03T20:56:35.450686+01" + + parsed = parse(text) + + assert parsed.year == 2008 + assert parsed.month == 9 + assert parsed.day == 3 + assert parsed.hour == 20 + assert parsed.minute == 56 + assert parsed.second == 35 + assert parsed.microsecond == 450686 + assert parsed.utcoffset().total_seconds() == 3600 + + +def test_iso8601_week_number(): + text = "2012-W05" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 1 + assert parsed.day == 30 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2012W05" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 1 + assert parsed.day == 30 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + # Long Year + text = "2015W53" + + parsed = parse(text) + + assert parsed.year == 2015 + assert parsed.month == 12 + assert parsed.day == 28 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2012-W05-5" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 2 + assert parsed.day == 3 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2012W055" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 2 + assert parsed.day == 3 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2009-W53-7" + parsed = parse(text) + + assert parsed.year == 2010 + assert parsed.month == 1 + assert parsed.day == 3 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2009-W01-1" + parsed = parse(text) + + assert parsed.year == 2008 + assert parsed.month == 12 + assert parsed.day == 29 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_iso8601_week_number_with_time(): + text = "2012-W05T09" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 1 + assert parsed.day == 30 + assert parsed.hour == 9 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2012W05T09" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 1 + assert parsed.day == 30 + assert parsed.hour == 9 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2012-W05-5T09" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 2 + assert parsed.day == 3 + assert parsed.hour == 9 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2012W055T09" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 2 + assert parsed.day == 3 + assert parsed.hour == 9 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_iso8601_ordinal(): + text = "2012-007" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 1 + assert parsed.day == 7 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "2012007" + + parsed = parse(text) + + assert parsed.year == 2012 + assert parsed.month == 1 + assert parsed.day == 7 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_iso8601_time(): + now = pendulum.datetime(2015, 11, 12) + + text = "201205" + + parsed = parse(text, now=now) + + assert parsed.year == 2015 + assert parsed.month == 11 + assert parsed.day == 12 + assert parsed.hour == 20 + assert parsed.minute == 12 + assert parsed.second == 5 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "20:12:05" + + parsed = parse(text, now=now) + + assert parsed.year == 2015 + assert parsed.month == 11 + assert parsed.day == 12 + assert parsed.hour == 20 + assert parsed.minute == 12 + assert parsed.second == 5 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "20:12:05.123456" + + parsed = parse(text, now=now) + + assert parsed.year == 2015 + assert parsed.month == 11 + assert parsed.day == 12 + assert parsed.hour == 20 + assert parsed.minute == 12 + assert parsed.second == 5 + assert parsed.microsecond == 123456 + assert parsed.tzinfo is None + + +def test_iso8601_ordinal_invalid(): + text = "2012-007-05" + + with pytest.raises(ParserError): + parse(text) + + +def test_exact(): + text = "2012" + + parsed = parse(text, exact=True) + + assert isinstance(parsed, datetime.date) + assert parsed.year == 2012 + assert parsed.month == 1 + assert parsed.day == 1 + + text = "2012-03" + + parsed = parse(text, exact=True) + + assert isinstance(parsed, datetime.date) + assert parsed.year == 2012 + assert parsed.month == 3 + assert parsed.day == 1 + + text = "2012-03-13" + + parsed = parse(text, exact=True) + + assert isinstance(parsed, datetime.date) + assert parsed.year == 2012 + assert parsed.month == 3 + assert parsed.day == 13 + + text = "2012W055" + + parsed = parse(text, exact=True) + + assert isinstance(parsed, datetime.date) + assert parsed.year == 2012 + assert parsed.month == 2 + assert parsed.day == 3 + + text = "2012007" + + parsed = parse(text, exact=True) + + assert isinstance(parsed, datetime.date) + assert parsed.year == 2012 + assert parsed.month == 1 + assert parsed.day == 7 + + text = "20:12:05" + + parsed = parse(text, exact=True) + + assert isinstance(parsed, datetime.time) + assert parsed.hour == 20 + assert parsed.minute == 12 + assert parsed.second == 5 + assert parsed.microsecond == 0 + + +def test_edge_cases(): + text = "2013-11-1" + + parsed = parse(text, strict=False) + assert parsed.year == 2013 + assert parsed.month == 11 + assert parsed.day == 1 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "10-01-01" + + parsed = parse(text, strict=False) + assert parsed.year == 2010 + assert parsed.month == 1 + assert parsed.day == 1 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "31-01-01" + + parsed = parse(text, strict=False) + assert parsed.year == 2031 + assert parsed.month == 1 + assert parsed.day == 1 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + text = "32-01-01" + + parsed = parse(text, strict=False) + assert parsed.year == 2032 + assert parsed.month == 1 + assert parsed.day == 1 + assert parsed.hour == 0 + assert parsed.minute == 0 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_strict(): + text = "4 Aug 2015 - 11:20 PM" + + with pytest.raises(ParserError): + parse(text) + + parsed = parse(text, strict=False) + assert parsed.year == 2015 + assert parsed.month == 8 + assert parsed.day == 4 + assert parsed.hour == 23 + assert parsed.minute == 20 + assert parsed.second == 0 + assert parsed.microsecond == 0 + assert parsed.tzinfo is None + + +def test_invalid(): + text = "201610T" + + with pytest.raises(ParserError): + parse(text) + + text = "2012-W54" + + with pytest.raises(ParserError): + parse(text) + + text = "2012-W13-8" + + with pytest.raises(ParserError): + parse(text) + + # W53 in normal year (not long) + text = "2017W53" + + with pytest.raises(ParserError): + parse(text) + + +def test_exif_edge_case(): + text = "2016:12:26 15:45:28" + + parsed = parse(text) + + assert parsed.year == 2016 + assert parsed.month == 12 + assert parsed.day == 26 + assert parsed.hour == 15 + assert parsed.minute == 45 + assert parsed.second == 28 diff --git a/tests/parsing/test_parsing_duration.py b/tests/parsing/test_parsing_duration.py new file mode 100644 index 0000000..ab8b992 --- /dev/null +++ b/tests/parsing/test_parsing_duration.py @@ -0,0 +1,298 @@ +from __future__ import annotations + +import pytest + +from pendulum.parsing import ParserError +from pendulum.parsing import parse + + +def test_parse_duration(): + text = "P2Y3M4DT5H6M7S" + parsed = parse(text) + + assert parsed.years == 2 + assert parsed.months == 3 + assert parsed.weeks == 0 + assert parsed.remaining_days == 4 + assert parsed.hours == 5 + assert parsed.minutes == 6 + assert parsed.remaining_seconds == 7 + assert parsed.microseconds == 0 + + text = "P1Y2M3DT4H5M6.5S" + parsed = parse(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 4 + assert parsed.minutes == 5 + assert parsed.remaining_seconds == 6 + assert parsed.microseconds == 500000 + + text = "P1Y2M3DT4H5M6,5S" + parsed = parse(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 4 + assert parsed.minutes == 5 + assert parsed.remaining_seconds == 6 + assert parsed.microseconds == 500000 + + text = "P1Y2M3D" + parsed = parse(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1Y2M3.5D" + parsed = parse(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1Y2M3,5D" + parsed = parse(text) + + assert parsed.years == 1 + assert parsed.months == 2 + assert parsed.weeks == 0 + assert parsed.remaining_days == 3 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "PT4H54M6.5S" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 4 + assert parsed.minutes == 54 + assert parsed.remaining_seconds == 6 + assert parsed.microseconds == 500000 + + text = "PT4H54M6,5S" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 4 + assert parsed.minutes == 54 + assert parsed.remaining_seconds == 6 + assert parsed.microseconds == 500000 + + text = "P1Y" + parsed = parse(text) + + assert parsed.years == 1 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1.5Y" + with pytest.raises(ParserError): + parse(text) + + text = "P1,5Y" + with pytest.raises(ParserError): + parse(text) + + text = "P1M" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 1 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1.5M" + with pytest.raises(ParserError): + parse(text) + + text = "P1,5M" + with pytest.raises(ParserError): + parse(text) + + text = "P1W" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 1 + assert parsed.remaining_days == 0 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1.5W" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 1 + assert parsed.remaining_days == 3 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1,5W" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 1 + assert parsed.remaining_days == 3 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1D" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 1 + assert parsed.hours == 0 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1.5D" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 1 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "P1,5D" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 1 + assert parsed.hours == 12 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "PT1H" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 1 + assert parsed.minutes == 0 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "PT1.5H" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 1 + assert parsed.minutes == 30 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + text = "PT1,5H" + parsed = parse(text) + + assert parsed.years == 0 + assert parsed.months == 0 + assert parsed.weeks == 0 + assert parsed.remaining_days == 0 + assert parsed.hours == 1 + assert parsed.minutes == 30 + assert parsed.remaining_seconds == 0 + assert parsed.microseconds == 0 + + +def test_parse_duration_no_operator(): + with pytest.raises(ParserError): + parse("2Y3M4DT5H6M7S") + + +def test_parse_duration_weeks_combined(): + with pytest.raises(ParserError): + parse("P1Y2W") + + +def test_parse_duration_invalid_order(): + with pytest.raises(ParserError): + parse("P1S") + + with pytest.raises(ParserError): + parse("P1D1S") + + with pytest.raises(ParserError): + parse("1Y2M3D1SPT1M") + + with pytest.raises(ParserError): + parse("P1Y2M3D2MT1S") + + with pytest.raises(ParserError): + parse("P2M3D1ST1Y1M") + + with pytest.raises(ParserError): + parse("P1Y2M2MT3D1S") + + with pytest.raises(ParserError): + parse("P1D1Y1M") + + with pytest.raises(ParserError): + parse("PT1S1H") + + +def test_parse_duration_invalid(): + with pytest.raises(ParserError): + parse("P1Dasdfasdf") + + +def test_parse_duration_fraction_only_allowed_on_last_component(): + with pytest.raises(ParserError): + parse("P2Y3M4DT5.5H6M7S") diff --git a/tests/test_helpers.py b/tests/test_helpers.py new file mode 100644 index 0000000..e3daeac --- /dev/null +++ b/tests/test_helpers.py @@ -0,0 +1,179 @@ +from __future__ import annotations + +from datetime import datetime + +import pytest +import pytz + +import pendulum + +from pendulum import timezone +from pendulum.helpers import days_in_year +from pendulum.helpers import precise_diff +from pendulum.helpers import week_day + + +def assert_diff( + diff, years=0, months=0, days=0, hours=0, minutes=0, seconds=0, microseconds=0 +): + assert diff.years == years + assert diff.months == months + assert diff.days == days + assert diff.hours == hours + assert diff.minutes == minutes + assert diff.seconds == seconds + assert diff.microseconds == microseconds + + +def test_precise_diff(): + dt1 = datetime(2003, 3, 1, 0, 0, 0) + dt2 = datetime(2003, 1, 31, 23, 59, 59) + + diff = precise_diff(dt1, dt2) + assert_diff(diff, months=-1, seconds=-1) + + diff = precise_diff(dt2, dt1) + assert_diff(diff, months=1, seconds=1) + + dt1 = datetime(2012, 3, 1, 0, 0, 0) + dt2 = datetime(2012, 1, 31, 23, 59, 59) + + diff = precise_diff(dt1, dt2) + assert_diff(diff, months=-1, seconds=-1) + + diff = precise_diff(dt2, dt1) + assert_diff(diff, months=1, seconds=1) + + dt1 = datetime(2001, 1, 1) + dt2 = datetime(2003, 9, 17, 20, 54, 47, 282310) + + diff = precise_diff(dt1, dt2) + assert_diff( + diff, + years=2, + months=8, + days=16, + hours=20, + minutes=54, + seconds=47, + microseconds=282310, + ) + + dt1 = datetime(2017, 2, 17, 16, 5, 45, 123456) + dt2 = datetime(2018, 2, 17, 16, 5, 45, 123256) + + diff = precise_diff(dt1, dt2) + assert_diff( + diff, months=11, days=30, hours=23, minutes=59, seconds=59, microseconds=999800 + ) + + # DST + tz = timezone("America/Toronto") + dt1 = tz.datetime(2017, 3, 7) + dt2 = tz.datetime(2017, 3, 13) + + diff = precise_diff(dt1, dt2) + assert_diff(diff, days=6, hours=0) + + +def test_precise_diff_timezone(): + paris = pendulum.timezone("Europe/Paris") + toronto = pendulum.timezone("America/Toronto") + + dt1 = paris.datetime(2013, 3, 31, 1, 30) + dt2 = paris.datetime(2013, 4, 1, 1, 30) + + diff = precise_diff(dt1, dt2) + assert_diff(diff, days=1, hours=0) + + dt2 = toronto.datetime(2013, 4, 1, 1, 30) + + diff = precise_diff(dt1, dt2) + assert_diff(diff, days=1, hours=5) + + # pytz + paris = pytz.timezone("Europe/Paris") + toronto = pytz.timezone("America/Toronto") + + dt1 = paris.localize(datetime(2013, 3, 31, 1, 30)) + dt2 = paris.localize(datetime(2013, 4, 1, 1, 30)) + + diff = precise_diff(dt1, dt2) + assert_diff(diff, days=1, hours=0) + + dt2 = toronto.localize(datetime(2013, 4, 1, 1, 30)) + + diff = precise_diff(dt1, dt2) + assert_diff(diff, days=1, hours=5) + + # Issue238 + dt1 = timezone("UTC").datetime(2018, 6, 20, 1, 30) + dt2 = timezone("Europe/Paris").datetime(2018, 6, 20, 3, 40) # UTC+2 + diff = precise_diff(dt1, dt2) + assert_diff(diff, minutes=10) + + +def test_week_day(): + assert week_day(2017, 6, 2) == 5 + assert week_day(2017, 1, 1) == 7 + + +def test_days_in_years(): + assert days_in_year(2017) == 365 + assert days_in_year(2016) == 366 + + +def test_locale(): + dt = pendulum.datetime(2000, 11, 10, 12, 34, 56, 123456) + pendulum.set_locale("fr") + + assert pendulum.get_locale() == "fr" + + assert dt.format("MMMM") == "novembre" + assert dt.date().format("MMMM") == "novembre" + + +def test_set_locale_invalid(): + with pytest.raises(ValueError): + pendulum.set_locale("invalid") + + +@pytest.mark.parametrize( + "locale", ["DE", "pt-BR", "pt-br", "PT-br", "PT-BR", "pt_br", "PT_BR", "PT_BR"] +) +def test_set_locale_malformed_locale(locale): + pendulum.set_locale(locale) + + pendulum.set_locale("en") + + +def test_week_starts_at(): + pendulum.week_starts_at(pendulum.SATURDAY) + + dt = pendulum.now().start_of("week") + assert dt.day_of_week == pendulum.SATURDAY + assert dt.date().day_of_week == pendulum.SATURDAY + + +def test_week_starts_at_invalid_value(): + with pytest.raises(ValueError): + pendulum.week_starts_at(-1) + + with pytest.raises(ValueError): + pendulum.week_starts_at(11) + + +def test_week_ends_at(): + pendulum.week_ends_at(pendulum.SATURDAY) + + dt = pendulum.now().end_of("week") + assert dt.day_of_week == pendulum.SATURDAY + assert dt.date().day_of_week == pendulum.SATURDAY + + +def test_week_ends_at_invalid_value(): + with pytest.raises(ValueError): + pendulum.week_ends_at(-1) + + with pytest.raises(ValueError): + pendulum.week_ends_at(11) diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..1710bf2 --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +import pytz + +from pendulum import _safe_timezone +from pendulum.tz.timezone import Timezone + + +def test_safe_timezone_with_tzinfo_objects(): + tz = _safe_timezone(pytz.timezone("Europe/Paris")) + + assert isinstance(tz, Timezone) + assert tz.name == "Europe/Paris" diff --git a/tests/test_parsing.py b/tests/test_parsing.py new file mode 100644 index 0000000..0e5308c --- /dev/null +++ b/tests/test_parsing.py @@ -0,0 +1,141 @@ +from __future__ import annotations + +import pendulum + +from tests.conftest import assert_date +from tests.conftest import assert_datetime +from tests.conftest import assert_duration +from tests.conftest import assert_time + + +def test_parse(): + text = "2016-10-16T12:34:56.123456+01:30" + + dt = pendulum.parse(text) + + assert isinstance(dt, pendulum.DateTime) + assert_datetime(dt, 2016, 10, 16, 12, 34, 56, 123456) + assert dt.tz.name == "+01:30" + assert dt.offset == 5400 + + text = "2016-10-16" + + dt = pendulum.parse(text) + + assert isinstance(dt, pendulum.DateTime) + assert_datetime(dt, 2016, 10, 16, 0, 0, 0, 0) + assert dt.offset == 0 + + with pendulum.travel_to(pendulum.datetime(2015, 11, 12), freeze=True): + text = "12:34:56.123456" + + dt = pendulum.parse(text) + + assert isinstance(dt, pendulum.DateTime) + assert_datetime(dt, 2015, 11, 12, 12, 34, 56, 123456) + assert dt.offset == 0 + + +def test_parse_with_timezone(): + text = "2016-10-16T12:34:56.123456" + + dt = pendulum.parse(text, tz="Europe/Paris") + assert_datetime(dt, 2016, 10, 16, 12, 34, 56, 123456) + assert dt.tz.name == "Europe/Paris" + assert dt.offset == 7200 + + +def test_parse_exact(): + text = "2016-10-16T12:34:56.123456+01:30" + + dt = pendulum.parse(text, exact=True) + + assert isinstance(dt, pendulum.DateTime) + assert_datetime(dt, 2016, 10, 16, 12, 34, 56, 123456) + assert dt.offset == 5400 + + text = "2016-10-16" + + dt = pendulum.parse(text, exact=True) + + assert isinstance(dt, pendulum.Date) + assert_date(dt, 2016, 10, 16) + + text = "12:34:56.123456" + + dt = pendulum.parse(text, exact=True) + + assert isinstance(dt, pendulum.Time) + assert_time(dt, 12, 34, 56, 123456) + + text = "13:00" + + dt = pendulum.parse(text, exact=True) + + assert isinstance(dt, pendulum.Time) + assert_time(dt, 13, 0, 0) + + +def test_parse_duration(): + text = "P2Y3M4DT5H6M7S" + + duration = pendulum.parse(text) + + assert isinstance(duration, pendulum.Duration) + assert_duration(duration, 2, 3, 0, 4, 5, 6, 7) + + text = "P2W" + + duration = pendulum.parse(text) + + assert isinstance(duration, pendulum.Duration) + assert_duration(duration, 0, 0, 2, 0, 0, 0, 0) + + +def test_parse_interval(): + text = "2008-05-11T15:30:00Z/P1Y2M10DT2H30M" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Interval) + assert_datetime(period.start, 2008, 5, 11, 15, 30, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2009, 7, 21, 18, 0, 0, 0) + assert period.end.offset == 0 + + text = "P1Y2M10DT2H30M/2008-05-11T15:30:00Z" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Interval) + assert_datetime(period.start, 2007, 3, 1, 13, 0, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) + assert period.end.offset == 0 + + text = "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Interval) + assert_datetime(period.start, 2007, 3, 1, 13, 0, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) + assert period.end.offset == 0 + + +def test_parse_now(): + dt = pendulum.parse("now") + + assert dt.timezone_name == "America/Toronto" + + mock_now = pendulum.yesterday() + + with pendulum.travel_to(mock_now, freeze=True): + assert pendulum.parse("now") == mock_now + + +def test_parse_with_utc_timezone(): + dt = pendulum.parse("2020-02-05T20:05:37.364951Z") + + assert dt.to_iso8601_string() == "2020-02-05T20:05:37.364951Z" diff --git a/tests/testing/__init__.py b/tests/testing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/testing/test_time_travel.py b/tests/testing/test_time_travel.py new file mode 100644 index 0000000..dd496e3 --- /dev/null +++ b/tests/testing/test_time_travel.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from time import sleep +from typing import TYPE_CHECKING + +import pytest + +import pendulum + +from pendulum.utils._compat import PYPY + +if TYPE_CHECKING: + from typing import Generator + + +@pytest.fixture(autouse=True) +def setup() -> Generator[None, None, None]: + pendulum.travel_back() + + yield + + pendulum.travel_back() + + +@pytest.mark.skipif(PYPY, reason="Time travelling not available on PyPy") +def test_travel() -> None: + now = pendulum.now() + + pendulum.travel(minutes=5) + + assert pendulum.now().diff_for_humans(now) == "5 minutes after" + + +@pytest.mark.skipif(PYPY, reason="Time travelling not available on PyPy") +def test_travel_with_frozen_time() -> None: + pendulum.travel(minutes=5, freeze=True) + + now = pendulum.now() + + sleep(0.01) + + assert now == pendulum.now() + + +@pytest.mark.skipif(PYPY, reason="Time travelling not available on PyPy") +def test_travel_to() -> None: + dt = pendulum.datetime(2022, 1, 19, tz="local") + + pendulum.travel_to(dt) + + assert pendulum.now().date() == dt.date() + + +@pytest.mark.skipif(PYPY, reason="Time travelling not available on PyPy") +def test_freeze() -> None: + pendulum.freeze() + + pendulum.travel(minutes=5) + + assert pendulum.now() == pendulum.now() + + pendulum.travel_back() + + pendulum.travel(minutes=5) + + now = pendulum.now() + + sleep(0.01) + + assert now != pendulum.now() + + pendulum.freeze() + + assert pendulum.now() == pendulum.now() + + pendulum.travel_back() + + with pendulum.freeze(): + assert pendulum.now() == pendulum.now() + + now = pendulum.now() + + sleep(0.01) + + assert now != pendulum.now() diff --git a/tests/time/__init__.py b/tests/time/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/time/test_add.py b/tests/time/test_add.py new file mode 100644 index 0000000..7075ebe --- /dev/null +++ b/tests/time/test_add.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +from datetime import timedelta + +import pytest + +import pendulum + + +def test_add_hours_positive(): + assert pendulum.time(12, 34, 56).add(hours=1).hour == 13 + + +def test_add_hours_zero(): + assert pendulum.time(12, 34, 56).add(hours=0).hour == 12 + + +def test_add_hours_negative(): + assert pendulum.time(12, 34, 56).add(hours=-1).hour == 11 + + +def test_add_minutes_positive(): + assert pendulum.time(12, 34, 56).add(minutes=1).minute == 35 + + +def test_add_minutes_zero(): + assert pendulum.time(12, 34, 56).add(minutes=0).minute == 34 + + +def test_add_minutes_negative(): + assert pendulum.time(12, 34, 56).add(minutes=-1).minute == 33 + + +def test_add_seconds_positive(): + assert pendulum.time(12, 34, 56).add(seconds=1).second == 57 + + +def test_add_seconds_zero(): + assert pendulum.time(12, 34, 56).add(seconds=0).second == 56 + + +def test_add_seconds_negative(): + assert pendulum.time(12, 34, 56).add(seconds=-1).second == 55 + + +def test_add_timedelta(): + delta = timedelta(seconds=45, microseconds=123456) + d = pendulum.time(3, 12, 15, 654321) + + d = d.add_timedelta(delta) + assert d.minute == 13 + assert d.second == 0 + assert d.microsecond == 777777 + + d = pendulum.time(3, 12, 15, 654321) + + d = d + delta + assert d.minute == 13 + assert d.second == 0 + assert d.microsecond == 777777 + + +def test_add_timedelta_with_days(): + delta = timedelta(days=3, seconds=45, microseconds=123456) + d = pendulum.time(3, 12, 15, 654321) + + with pytest.raises(TypeError): + d.add_timedelta(delta) + + +def test_addition_invalid_type(): + d = pendulum.time(3, 12, 15, 654321) + + with pytest.raises(TypeError): + d + 3 + + with pytest.raises(TypeError): + 3 + d diff --git a/tests/time/test_behavior.py b/tests/time/test_behavior.py new file mode 100644 index 0000000..0071c94 --- /dev/null +++ b/tests/time/test_behavior.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +import pickle + +from datetime import time + +import pytest + +import pendulum + +from pendulum import Time + + +@pytest.fixture() +def p(): + return pendulum.Time(12, 34, 56, 123456, tzinfo=pendulum.timezone("Europe/Paris")) + + +@pytest.fixture() +def d(): + return time(12, 34, 56, 123456, tzinfo=pendulum.timezone("Europe/Paris")) + + +def test_hash(p, d): + assert hash(d) == hash(p) + dt1 = Time(12, 34, 57, 123456) + + assert hash(p) != hash(dt1) + + +def test_pickle(): + dt1 = Time(12, 34, 56, 123456) + s = pickle.dumps(dt1) + dt2 = pickle.loads(s) + + assert dt2 == dt1 + + +def test_utcoffset(p, d): + assert d.utcoffset() == p.utcoffset() + + +def test_dst(p, d): + assert d.dst() == p.dst() + + +def test_tzname(p, d): + assert d.tzname() == p.tzname() + assert Time(12, 34, 56, 123456).tzname() == time(12, 34, 56, 123456).tzname() diff --git a/tests/time/test_comparison.py b/tests/time/test_comparison.py new file mode 100644 index 0000000..f1ef275 --- /dev/null +++ b/tests/time/test_comparison.py @@ -0,0 +1,185 @@ +from __future__ import annotations + +from datetime import time + +import pendulum + +from tests.conftest import assert_time + + +def test_equal_to_true(): + t1 = pendulum.time(1, 2, 3) + t2 = pendulum.time(1, 2, 3) + t3 = time(1, 2, 3) + + assert t1 == t2 + assert t1 == t3 + + +def test_equal_to_false(): + t1 = pendulum.time(1, 2, 3) + t2 = pendulum.time(1, 2, 4) + t3 = time(1, 2, 4) + + assert t1 != t2 + assert t1 != t3 + + +def test_not_equal_to_none(): + t1 = pendulum.time(1, 2, 3) + + assert t1 != None # noqa + + +def test_greater_than_true(): + t1 = pendulum.time(1, 2, 3) + t2 = pendulum.time(1, 2, 2) + t3 = time(1, 2, 2) + + assert t1 > t2 + assert t1 > t3 + + +def test_greater_than_false(): + t1 = pendulum.time(1, 2, 2) + t2 = pendulum.time(1, 2, 3) + t3 = time(1, 2, 3) + + assert not t1 > t2 + assert not t1 > t3 + + +def test_greater_than_or_equal_true(): + t1 = pendulum.time(1, 2, 3) + t2 = pendulum.time(1, 2, 2) + t3 = time(1, 2, 2) + + assert t1 >= t2 + assert t1 >= t3 + + +def test_greater_than_or_equal_true_equal(): + t1 = pendulum.time(1, 2, 3) + t2 = pendulum.time(1, 2, 3) + t3 = time(1, 2, 3) + + assert t1 >= t2 + assert t1 >= t3 + + +def test_greater_than_or_equal_false(): + t1 = pendulum.time(1, 2, 2) + t2 = pendulum.time(1, 2, 3) + t3 = time(1, 2, 3) + + assert not t1 >= t2 + assert not t1 >= t3 + + +def test_less_than_true(): + t1 = pendulum.time(1, 2, 2) + t2 = pendulum.time(1, 2, 3) + t3 = time(1, 2, 3) + + assert t1 < t2 + assert t1 < t3 + + +def test_less_than_false(): + t1 = pendulum.time(1, 2, 3) + t2 = pendulum.time(1, 2, 2) + t3 = time(1, 2, 2) + + assert not t1 < t2 + assert not t1 < t3 + + +def test_less_than_or_equal_true(): + t1 = pendulum.time(1, 2, 2) + t2 = pendulum.time(1, 2, 3) + t3 = time(1, 2, 3) + + assert t1 <= t2 + assert t1 <= t3 + + +def test_less_than_or_equal_true_equal(): + t1 = pendulum.time(1, 2, 3) + t2 = pendulum.time(1, 2, 3) + t3 = time(1, 2, 3) + + assert t1 <= t2 + assert t1 <= t3 + + +def test_less_than_or_equal_false(): + t1 = pendulum.time(1, 2, 3) + t2 = pendulum.time(1, 2, 2) + t3 = time(1, 2, 2) + + assert not t1 <= t2 + assert not t1 <= t3 + + +def test_closest(): + instance = pendulum.time(12, 34, 56) + t1 = pendulum.time(12, 34, 54) + t2 = pendulum.time(12, 34, 59) + closest = instance.closest(t1, t2) + assert t1 == closest + + closest = instance.closest(t2, t1) + assert t1 == closest + + +def test_closest_with_time(): + instance = pendulum.time(12, 34, 56) + t1 = pendulum.time(12, 34, 54) + t2 = pendulum.time(12, 34, 59) + closest = instance.closest(t1, t2) + + assert_time(closest, 12, 34, 54) + + +def test_closest_with_equals(): + instance = pendulum.time(12, 34, 56) + t1 = pendulum.time(12, 34, 56) + t2 = pendulum.time(12, 34, 59) + closest = instance.closest(t1, t2) + assert t1 == closest + + +def test_farthest(): + instance = pendulum.time(12, 34, 56) + t1 = pendulum.time(12, 34, 54) + t2 = pendulum.time(12, 34, 59) + farthest = instance.farthest(t1, t2) + assert t2 == farthest + + farthest = instance.farthest(t2, t1) + assert t2 == farthest + + +def test_farthest_with_time(): + instance = pendulum.time(12, 34, 56) + t1 = pendulum.time(12, 34, 54) + t2 = pendulum.time(12, 34, 59) + farthest = instance.farthest(t1, t2) + + assert_time(farthest, 12, 34, 59) + + +def test_farthest_with_equals(): + instance = pendulum.time(12, 34, 56) + t1 = pendulum.time(12, 34, 56) + t2 = pendulum.time(12, 34, 59) + + farthest = instance.farthest(t1, t2) + assert t2 == farthest + + +def test_comparison_to_unsupported(): + t1 = pendulum.now().time() + + assert t1 != "test" + assert t1 not in ["test"] diff --git a/tests/time/test_construct.py b/tests/time/test_construct.py new file mode 100644 index 0000000..7d81b37 --- /dev/null +++ b/tests/time/test_construct.py @@ -0,0 +1,22 @@ +from __future__ import annotations + +import pendulum + +from tests.conftest import assert_time + + +def test_init(): + t = pendulum.time(12, 34, 56, 123456) + + assert_time(t, 12, 34, 56, 123456) + + +def test_init_with_missing_values(): + t = pendulum.time(12, 34, 56) + assert_time(t, 12, 34, 56, 0) + + t = pendulum.time(12, 34) + assert_time(t, 12, 34, 0, 0) + + t = pendulum.time(12) + assert_time(t, 12, 0, 0, 0) diff --git a/tests/time/test_diff.py b/tests/time/test_diff.py new file mode 100644 index 0000000..629a058 --- /dev/null +++ b/tests/time/test_diff.py @@ -0,0 +1,350 @@ +from __future__ import annotations + +import pendulum + +from pendulum import Time + + +def test_diff_in_hours_positive(): + dt = Time(12, 34, 56) + assert dt.diff(dt.add(hours=2).add(seconds=3672)).in_hours() == 3 + + +def test_diff_in_hours_negative_with_sign(): + dt = Time(12, 34, 56) + assert dt.diff(dt.subtract(hours=2).add(seconds=3600), False).in_hours() == -1 + + +def test_diff_in_hours_negative_no_sign(): + dt = Time(12, 34, 56) + assert dt.diff(dt.subtract(hours=2).add(seconds=3600)).in_hours() == 1 + + +def test_diff_in_hours_vs_default_now(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.subtract(hours=2).diff().in_hours() == 2 + + +def test_diff_in_hours_ensure_is_truncated(): + dt = Time(12, 34, 56) + assert dt.diff(dt.add(hours=2).add(seconds=5401)).in_hours() == 3 + + +def test_diff_in_minutes_positive(): + dt = Time(12, 34, 56) + assert dt.diff(dt.add(hours=1).add(minutes=2)).in_minutes() == 62 + + +def test_diff_in_minutes_positive_big(): + dt = Time(12, 34, 56) + assert dt.diff(dt.add(hours=25).add(minutes=2)).in_minutes() == 62 + + +def test_diff_in_minutes_negative_with_sign(): + dt = Time(12, 34, 56) + assert dt.diff(dt.subtract(hours=1).add(minutes=2), False).in_minutes() == -58 + + +def test_diff_in_minutes_negative_no_sign(): + dt = Time(12, 34, 56) + 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.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.subtract(hours=1).diff().in_minutes() == 60 + + +def test_diff_in_minutes_ensure_is_truncated(): + dt = Time(12, 34, 56) + assert dt.diff(dt.add(minutes=1).add(seconds=59)).in_minutes() == 1 + + +def test_diff_in_seconds_positive(): + dt = Time(12, 34, 56) + assert dt.diff(dt.add(minutes=1).add(seconds=2)).in_seconds() == 62 + + +def test_diff_in_seconds_positive_big(): + dt = Time(12, 34, 56) + assert dt.diff(dt.add(hours=2).add(seconds=2)).in_seconds() == 7202 + + +def test_diff_in_seconds_negative_with_sign(): + dt = Time(12, 34, 56) + assert dt.diff(dt.subtract(minutes=1).add(seconds=2), False).in_seconds() == -58 + + +def test_diff_in_seconds_negative_no_sign(): + dt = Time(12, 34, 56) + 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.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.subtract(hours=1).diff().in_seconds() == 3600 + + +def test_diff_in_seconds_ensure_is_truncated(): + dt = Time(12, 34, 56) + assert dt.diff(dt.add(seconds=1.9)).in_seconds() == 1 + + +def test_diff_for_humans_now_and_second(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans() == "a few seconds ago" + + +def test_diff_for_humans_now_and_seconds(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert 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.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.subtract(seconds=59).diff_for_humans() == "59 seconds ago" + + +def test_diff_for_humans_now_and_minute(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.subtract(minutes=1).diff_for_humans() == "1 minute ago" + + +def test_diff_for_humans_now_and_minutes(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.subtract(minutes=2).diff_for_humans() == "2 minutes ago" + + +def test_diff_for_humans_now_and_nearly_hour(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.subtract(minutes=59).diff_for_humans() == "59 minutes ago" + + +def test_diff_for_humans_now_and_hour(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.subtract(hours=1).diff_for_humans() == "1 hour ago" + + +def test_diff_for_humans_now_and_hours(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.subtract(hours=2).diff_for_humans() == "2 hours ago" + + +def test_diff_for_humans_now_and_future_second(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert 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.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert 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.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.add(seconds=59).diff_for_humans() == "in 59 seconds" + + +def test_diff_for_humans_now_and_future_minute(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.add(minutes=1).diff_for_humans() == "in 1 minute" + + +def test_diff_for_humans_now_and_future_minutes(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert 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.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.add(minutes=59).diff_for_humans() == "in 59 minutes" + + +def test_diff_for_humans_now_and_future_hour(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.add(hours=1).diff_for_humans() == "in 1 hour" + + +def test_diff_for_humans_now_and_future_hours(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.add(hours=2).diff_for_humans() == "in 2 hours" + + +def test_diff_for_humans_other_and_second(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(seconds=1)) == "a few seconds before" + + +def test_diff_for_humans_other_and_seconds(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(seconds=2)) == "a few seconds before" + + +def test_diff_for_humans_other_and_nearly_minute(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(seconds=59)) == "59 seconds before" + + +def test_diff_for_humans_other_and_minute(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(minutes=1)) == "1 minute before" + + +def test_diff_for_humans_other_and_minutes(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(minutes=2)) == "2 minutes before" + + +def test_diff_for_humans_other_and_nearly_hour(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(minutes=59)) == "59 minutes before" + + +def test_diff_for_humans_other_and_hour(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(hours=1)) == "1 hour before" + + +def test_diff_for_humans_other_and_hours(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(hours=2)) == "2 hours before" + + +def test_diff_for_humans_other_and_future_second(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(seconds=1)) == "a few seconds after" + + +def test_diff_for_humans_other_and_future_seconds(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(seconds=2)) == "a few seconds after" + + +def test_diff_for_humans_other_and_nearly_future_minute(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(seconds=59)) == "59 seconds after" + + +def test_diff_for_humans_other_and_future_minute(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(minutes=1)) == "1 minute after" + + +def test_diff_for_humans_other_and_future_minutes(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(minutes=2)) == "2 minutes after" + + +def test_diff_for_humans_other_and_nearly_future_hour(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(minutes=59)) == "59 minutes after" + + +def test_diff_for_humans_other_and_future_hour(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(hours=1)) == "1 hour after" + + +def test_diff_for_humans_other_and_future_hours(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(hours=2)) == "2 hours after" + + +def test_diff_for_humans_absolute_seconds(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(seconds=59), True) == "59 seconds" + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(seconds=59), True) == "59 seconds" + + +def test_diff_for_humans_absolute_minutes(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(minutes=30), True) == "30 minutes" + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(minutes=30), True) == "30 minutes" + + +def test_diff_for_humans_absolute_hours(): + with pendulum.travel_to(pendulum.today().at(12, 34, 56)): + now = pendulum.now().time() + + assert now.diff_for_humans(now.subtract(hours=3), True) == "3 hours" + now = pendulum.now().time() + + assert now.diff_for_humans(now.add(hours=3), True) == "3 hours" diff --git a/tests/time/test_fluent_setters.py b/tests/time/test_fluent_setters.py new file mode 100644 index 0000000..a678e56 --- /dev/null +++ b/tests/time/test_fluent_setters.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +from pendulum import Time +from tests.conftest import assert_time + + +def test_replace(): + t = Time(12, 34, 56, 123456) + t = t.replace(1, 2, 3, 654321) + + assert isinstance(t, Time) + assert_time(t, 1, 2, 3, 654321) diff --git a/tests/time/test_strings.py b/tests/time/test_strings.py new file mode 100644 index 0000000..db3c9cd --- /dev/null +++ b/tests/time/test_strings.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +from pendulum import Time + + +def test_to_string(): + d = Time(1, 2, 3) + assert str(d) == "01:02:03" + d = Time(1, 2, 3, 123456) + assert str(d) == "01:02:03.123456" + + +def test_repr(): + d = Time(1, 2, 3) + assert repr(d) == "Time(1, 2, 3)" + + d = Time(1, 2, 3, 123456) + assert repr(d) == "Time(1, 2, 3, 123456)" + + +def test_format_with_locale(): + d = Time(14, 15, 16) + assert d.format("hh:mm:ss A", locale="fr") == "02:15:16 PM" + + +def test_strftime(): + d = Time(14, 15, 16) + assert d.strftime("%H") == "14" + + +def test_for_json(): + d = Time(14, 15, 16) + assert d.for_json() == "14:15:16" + + +def test_format(): + d = Time(14, 15, 16) + assert f"{d}" == "14:15:16" + assert f"{d:mm}" == "15" diff --git a/tests/time/test_sub.py b/tests/time/test_sub.py new file mode 100644 index 0000000..1a957ad --- /dev/null +++ b/tests/time/test_sub.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +from datetime import time +from datetime import timedelta + +import pytest +import pytz + +import pendulum + +from pendulum import Time +from tests.conftest import assert_duration + + +def test_sub_hours_positive(): + assert Time(0, 0, 0).subtract(hours=1).hour == 23 + + +def test_sub_hours_zero(): + assert Time(0, 0, 0).subtract(hours=0).hour == 0 + + +def test_sub_hours_negative(): + assert Time(0, 0, 0).subtract(hours=-1).hour == 1 + + +def test_sub_minutes_positive(): + assert Time(0, 0, 0).subtract(minutes=1).minute == 59 + + +def test_sub_minutes_zero(): + assert Time(0, 0, 0).subtract(minutes=0).minute == 0 + + +def test_sub_minutes_negative(): + assert Time(0, 0, 0).subtract(minutes=-1).minute == 1 + + +def test_sub_seconds_positive(): + assert Time(0, 0, 0).subtract(seconds=1).second == 59 + + +def test_sub_seconds_zero(): + assert Time(0, 0, 0).subtract(seconds=0).second == 0 + + +def test_sub_seconds_negative(): + assert Time(0, 0, 0).subtract(seconds=-1).second == 1 + + +def test_subtract_timedelta(): + delta = timedelta(seconds=16, microseconds=654321) + d = Time(3, 12, 15, 777777) + + d = d.subtract_timedelta(delta) + assert d.minute == 11 + assert d.second == 59 + assert d.microsecond == 123456 + + d = Time(3, 12, 15, 777777) + + d = d - delta + assert d.minute == 11 + assert d.second == 59 + assert d.microsecond == 123456 + + +def test_add_timedelta_with_days(): + delta = timedelta(days=3, seconds=45, microseconds=123456) + d = Time(3, 12, 15, 654321) + + with pytest.raises(TypeError): + d.subtract_timedelta(delta) + + +def test_subtract_invalid_type(): + d = Time(0, 0, 0) + + with pytest.raises(TypeError): + d - "ab" + + with pytest.raises(TypeError): + "ab" - d + + +def test_subtract_time(): + t = Time(12, 34, 56) + t1 = Time(1, 1, 1) + t2 = time(1, 1, 1) + t3 = time(1, 1, 1, tzinfo=pytz.timezone("Europe/Paris")) + + diff = t - t1 + assert isinstance(diff, pendulum.Duration) + assert_duration(diff, 0, hours=11, minutes=33, seconds=55) + + diff = t1 - t + assert isinstance(diff, pendulum.Duration) + assert_duration(diff, 0, hours=-11, minutes=-33, seconds=-55) + + diff = t - t2 + assert isinstance(diff, pendulum.Duration) + assert_duration(diff, 0, hours=11, minutes=33, seconds=55) + + diff = t2 - t + assert isinstance(diff, pendulum.Duration) + assert_duration(diff, 0, hours=-11, minutes=-33, seconds=-55) + + with pytest.raises(TypeError): + t - t3 + + with pytest.raises(TypeError): + t3 - t diff --git a/tests/tz/__init__.py b/tests/tz/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/tz/test_helpers.py b/tests/tz/test_helpers.py new file mode 100644 index 0000000..edec6fd --- /dev/null +++ b/tests/tz/test_helpers.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +import pytest + +from pendulum.tz import timezone +from pendulum.tz.exceptions import InvalidTimezone +from pendulum.tz.timezone import FixedTimezone +from pendulum.tz.timezone import Timezone + + +def test_timezone_with_name(): + tz = timezone("Europe/Paris") + + assert isinstance(tz, Timezone) + assert tz.name == "Europe/Paris" + + +def test_timezone_with_invalid_name(): + with pytest.raises(InvalidTimezone): + timezone("Invalid") + + +def test_timezone_with_offset(): + tz = timezone(-19800) + + assert isinstance(tz, FixedTimezone) + assert tz.name == "-05:30" diff --git a/tests/tz/test_local_timezone.py b/tests/tz/test_local_timezone.py new file mode 100644 index 0000000..b8eff6d --- /dev/null +++ b/tests/tz/test_local_timezone.py @@ -0,0 +1,52 @@ +from __future__ import annotations + +import os +import sys + +import pytest + +from pendulum.tz.local_timezone import _get_unix_timezone +from pendulum.tz.local_timezone import _get_windows_timezone + + +@pytest.mark.skipif( + sys.platform == "win32", reason="Test only available for UNIX systems" +) +def test_unix_symlink(): + # A ZONE setting in the target path of a symbolic linked localtime, + # f ex systemd distributions + local_path = os.path.join(os.path.split(__file__)[0], "..") + tz = _get_unix_timezone(_root=os.path.join(local_path, "fixtures", "tz", "symlink")) + + assert tz.name == "Europe/Paris" + + +@pytest.mark.skipif( + sys.platform == "win32", reason="Test only available for UNIX systems" +) +def test_unix_clock(): + # A ZONE setting in the target path of a symbolic linked localtime, + # f ex systemd distributions + local_path = os.path.join(os.path.split(__file__)[0], "..") + tz = _get_unix_timezone(_root=os.path.join(local_path, "fixtures", "tz", "clock")) + + assert tz.name == "Europe/Zurich" + + +@pytest.mark.skipif(sys.platform != "win32", reason="Test only available for Windows") +def test_windows_timezone(): + timezone = _get_windows_timezone() + + assert timezone is not None + + +@pytest.mark.skipif( + sys.platform == "win32", reason="Test only available for UNIX systems" +) +def test_unix_etc_timezone_dir(): + # Should not fail if `/etc/timezone` is a folder + local_path = os.path.join(os.path.split(__file__)[0], "..") + root_path = os.path.join(local_path, "fixtures", "tz", "timezone_dir") + tz = _get_unix_timezone(_root=root_path) + + assert tz.name == "Europe/Paris" diff --git a/tests/tz/test_timezone.py b/tests/tz/test_timezone.py new file mode 100644 index 0000000..655267d --- /dev/null +++ b/tests/tz/test_timezone.py @@ -0,0 +1,447 @@ +from __future__ import annotations + +from datetime import datetime +from datetime import timedelta + +import pytest + +import pendulum + +from pendulum import timezone +from pendulum.tz import fixed_timezone +from pendulum.tz.exceptions import AmbiguousTime +from pendulum.tz.exceptions import NonExistingTime +from pendulum.utils._compat import zoneinfo +from tests.conftest import assert_datetime + + +@pytest.fixture(autouse=True) +def setup(): + pendulum.tz._tz_cache = {} + + yield + + pendulum.tz._tz_cache = {} + + +def test_basic_convert(): + dt = datetime(2016, 6, 1, 12, 34, 56, 123456, fold=1) + tz = timezone("Europe/Paris") + dt = tz.convert(dt) + + assert dt.year == 2016 + assert dt.month == 6 + assert dt.day == 1 + assert dt.hour == 12 + assert dt.minute == 34 + assert dt.second == 56 + assert dt.microsecond == 123456 + assert dt.tzinfo.name == "Europe/Paris" + assert dt.tzinfo.utcoffset(dt) == timedelta(seconds=7200) + assert dt.tzinfo.dst(dt) == timedelta(seconds=3600) + + +def test_skipped_time_with_pre_rule(): + dt = datetime(2013, 3, 31, 2, 30, 45, 123456, fold=0) + tz = timezone("Europe/Paris") + dt = tz.convert(dt) + + assert dt.year == 2013 + assert dt.month == 3 + assert dt.day == 31 + assert dt.hour == 1 + assert dt.minute == 30 + assert dt.second == 45 + assert dt.microsecond == 123456 + assert dt.tzinfo.name == "Europe/Paris" + assert dt.tzinfo.utcoffset(dt) == timedelta(seconds=3600) + assert dt.tzinfo.dst(dt) == timedelta() + + +def test_skipped_time_with_post_rule(): + dt = datetime(2013, 3, 31, 2, 30, 45, 123456, fold=1) + tz = timezone("Europe/Paris") + dt = tz.convert(dt) + + assert dt.year == 2013 + assert dt.month == 3 + assert dt.day == 31 + assert dt.hour == 3 + assert dt.minute == 30 + assert dt.second == 45 + assert dt.microsecond == 123456 + assert dt.tzinfo.name == "Europe/Paris" + assert dt.tzinfo.utcoffset(dt) == timedelta(seconds=7200) + assert dt.tzinfo.dst(dt) == timedelta(seconds=3600) + + +def test_skipped_time_with_error(): + dt = datetime(2013, 3, 31, 2, 30, 45, 123456) + tz = timezone("Europe/Paris") + with pytest.raises(NonExistingTime): + tz.convert(dt, raise_on_unknown_times=True) + + +def test_repeated_time(): + dt = datetime(2013, 10, 27, 2, 30, 45, 123456, fold=1) + tz = timezone("Europe/Paris") + dt = tz.convert(dt) + + assert dt.year == 2013 + assert dt.month == 10 + assert dt.day == 27 + assert dt.hour == 2 + assert dt.minute == 30 + assert dt.second == 45 + assert dt.microsecond == 123456 + assert dt.tzinfo.name == "Europe/Paris" + assert dt.tzinfo.utcoffset(dt) == timedelta(seconds=3600) + assert dt.tzinfo.dst(dt) == timedelta() + + +def test_repeated_time_pre_rule(): + dt = datetime(2013, 10, 27, 2, 30, 45, 123456, fold=0) + tz = timezone("Europe/Paris") + dt = tz.convert(dt) + + assert dt.year == 2013 + assert dt.month == 10 + assert dt.day == 27 + assert dt.hour == 2 + assert dt.minute == 30 + assert dt.second == 45 + assert dt.microsecond == 123456 + assert dt.tzinfo.name == "Europe/Paris" + assert dt.tzinfo.utcoffset(dt) == timedelta(seconds=7200) + assert dt.tzinfo.dst(dt) == timedelta(seconds=3600) + + +def test_repeated_time_with_error(): + dt = datetime(2013, 10, 27, 2, 30, 45, 123456) + tz = timezone("Europe/Paris") + with pytest.raises(AmbiguousTime): + tz.convert(dt, raise_on_unknown_times=True) + + +def test_pendulum_create_basic(): + dt = pendulum.datetime(2016, 6, 1, 12, 34, 56, 123456, tz="Europe/Paris") + + assert_datetime(dt, 2016, 6, 1, 12, 34, 56, 123456) + assert dt.timezone_name == "Europe/Paris" + assert dt.offset == 7200 + assert dt.is_dst() + + +def test_pendulum_create_skipped(): + dt = pendulum.datetime(2013, 3, 31, 2, 30, 45, 123456, tz="Europe/Paris") + + assert isinstance(dt, pendulum.DateTime) + assert_datetime(dt, 2013, 3, 31, 3, 30, 45, 123456) + assert dt.timezone_name == "Europe/Paris" + assert dt.tzinfo.utcoffset(dt) == timedelta(seconds=7200) + assert dt.tzinfo.dst(dt) == timedelta(seconds=3600) + + +def test_pendulum_create_skipped_with_pre_rule(): + dt = pendulum.datetime(2013, 3, 31, 2, 30, 45, 123456, tz="Europe/Paris", fold=0) + + assert_datetime(dt, 2013, 3, 31, 1, 30, 45, 123456) + assert dt.timezone_name == "Europe/Paris" + assert dt.tzinfo.utcoffset(dt) == timedelta(seconds=3600) + assert dt.tzinfo.dst(dt) == timedelta() + + +def test_pendulum_create_skipped_with_error(): + with pytest.raises(NonExistingTime): + pendulum.datetime( + 2013, + 3, + 31, + 2, + 30, + 45, + 123456, + tz="Europe/Paris", + raise_on_unknown_times=True, + ) + + +def test_pendulum_create_repeated(): + dt = pendulum.datetime(2013, 10, 27, 2, 30, 45, 123456, tz="Europe/Paris") + + assert_datetime(dt, 2013, 10, 27, 2, 30, 45, 123456) + assert dt.timezone_name == "Europe/Paris" + assert dt.tzinfo.utcoffset(dt) == timedelta(seconds=3600) + assert dt.tzinfo.dst(dt) == timedelta() + + +def test_pendulum_create_repeated_with_pre_rule(): + dt = pendulum.datetime( + 2013, + 10, + 27, + 2, + 30, + 45, + 123456, + tz="Europe/Paris", + fold=0, + ) + + assert_datetime(dt, 2013, 10, 27, 2, 30, 45, 123456) + assert dt.timezone_name == "Europe/Paris" + assert dt.tzinfo.utcoffset(dt) == timedelta(seconds=7200) + assert dt.tzinfo.dst(dt) == timedelta(seconds=3600) + + +def test_pendulum_create_repeated_with_error(): + with pytest.raises(AmbiguousTime): + pendulum.datetime( + 2013, + 10, + 27, + 2, + 30, + 45, + 123456, + tz="Europe/Paris", + raise_on_unknown_times=True, + ) + + +def test_convert_accept_pendulum_instance(): + dt = pendulum.datetime(2016, 8, 7, 12, 53, 54) + tz = timezone("Europe/Paris") + new = tz.convert(dt) + + assert isinstance(new, pendulum.DateTime) + assert_datetime(new, 2016, 8, 7, 14, 53, 54) + + +def test_utcoffset(): + tz = pendulum.timezone("America/Guayaquil") + utcoffset = tz.utcoffset(pendulum.now("UTC")) + assert utcoffset == timedelta(0, -18000) + + +def test_utcoffset_pre_transition(): + tz = pendulum.timezone("America/Chicago") + utcoffset = tz.utcoffset(datetime(1883, 11, 18)) + assert utcoffset == timedelta(days=-1, seconds=65364) + + +def test_dst(): + tz = pendulum.timezone("Europe/Amsterdam") + dst = tz.dst(datetime(1940, 7, 1)) + native_tz = zoneinfo.ZoneInfo("Europe/Amsterdam") + + assert dst == native_tz.dst(datetime(1940, 7, 1)) + + +def test_short_timezones_should_not_modify_time(): + tz = pendulum.timezone("EST") + dt = tz.datetime(2017, 6, 15, 14, 0, 0) + + assert dt.year == 2017 + assert dt.month == 6 + assert dt.day == 15 + assert dt.hour == 14 + assert dt.minute == 0 + assert dt.second == 0 + + tz = pendulum.timezone("HST") + dt = tz.datetime(2017, 6, 15, 14, 0, 0) + + assert dt.year == 2017 + assert dt.month == 6 + assert dt.day == 15 + assert dt.hour == 14 + assert dt.minute == 0 + assert dt.second == 0 + + +def test_after_last_transition(): + tz = pendulum.timezone("Europe/Paris") + dt = tz.datetime(2135, 6, 15, 14, 0, 0) + + assert dt.year == 2135 + assert dt.month == 6 + assert dt.day == 15 + assert dt.hour == 14 + assert dt.minute == 0 + assert dt.second == 0 + assert dt.microsecond == 0 + + +@pytest.mark.skip( + reason="zoneinfo does not currently support POSIX transition rules to go beyond the last fixed transition." +) +def test_on_last_transition(): + tz = pendulum.timezone("Europe/Paris") + dt = pendulum.naive(2037, 10, 25, 2, 30) + dt = tz.convert(dt, dst_rule=pendulum.POST_TRANSITION) + + assert dt.year == 2037 + assert dt.month == 10 + assert dt.day == 25 + assert dt.hour == 2 + assert dt.minute == 30 + assert dt.second == 0 + assert dt.microsecond == 0 + assert dt.utcoffset().total_seconds() == 3600 + + dt = pendulum.naive(2037, 10, 25, 2, 30) + dt = tz.convert(dt, dst_rule=pendulum.PRE_TRANSITION) + + assert dt.year == 2037 + assert dt.month == 10 + assert dt.day == 25 + assert dt.hour == 2 + assert dt.minute == 30 + assert dt.second == 0 + assert dt.microsecond == 0 + assert dt.utcoffset().total_seconds() == 7200 + + +def test_convert_fold_attribute_is_honored(): + tz = pendulum.timezone("US/Eastern") + dt = datetime(2014, 11, 2, 1, 30) + + new = tz.convert(dt) + assert new.strftime("%z") == "-0400" + + new = tz.convert(dt.replace(fold=1)) + assert new.strftime("%z") == "-0500" + + +def test_utcoffset_fold_attribute_is_honored(): + tz = pendulum.timezone("US/Eastern") + dt = datetime(2014, 11, 2, 1, 30) + + offset = tz.utcoffset(dt) + + assert offset.total_seconds() == -4 * 3600 + + offset = tz.utcoffset(dt.replace(fold=1)) + + assert offset.total_seconds() == -5 * 3600 + + +def test_dst_fold_attribute_is_honored(): + tz = pendulum.timezone("US/Eastern") + dt = datetime(2014, 11, 2, 1, 30) + + offset = tz.dst(dt) + + assert offset.total_seconds() == 3600 + + offset = tz.dst(dt.replace(fold=1)) + + assert offset.total_seconds() == 0 + + +def test_tzname_fold_attribute_is_honored(): + tz = pendulum.timezone("US/Eastern") + dt = datetime(2014, 11, 2, 1, 30) + + name = tz.tzname(dt) + + assert name == "EDT" + + name = tz.tzname(dt.replace(fold=1)) + + assert name == "EST" + + +def test_constructor_fold_attribute_is_honored(): + tz = pendulum.timezone("US/Eastern") + dt = datetime(2014, 11, 2, 1, 30, tzinfo=tz) + + assert dt.strftime("%z") == "-0400" + + dt = datetime(2014, 11, 2, 1, 30, tzinfo=tz, fold=1) + + assert dt.strftime("%z") == "-0500" + + +def test_datetime(): + tz = timezone("Europe/Paris") + + dt = tz.datetime(2013, 3, 24, 1, 30) + assert dt.year == 2013 + assert dt.month == 3 + assert dt.day == 24 + assert dt.hour == 1 + assert dt.minute == 30 + assert dt.second == 0 + assert dt.microsecond == 0 + + dt = tz.datetime(2013, 3, 31, 2, 30) + assert dt.year == 2013 + assert dt.month == 3 + assert dt.day == 31 + assert dt.hour == 3 + assert dt.minute == 30 + assert dt.second == 0 + assert dt.microsecond == 0 + + +def test_fixed_timezone(): + tz = fixed_timezone(19800) + tz2 = fixed_timezone(18000) + dt = datetime(2016, 11, 26, tzinfo=tz) + + assert tz2.utcoffset(dt).total_seconds() == 18000 + assert tz2.dst(dt) == timedelta() + + +def test_just_before_last_transition(): + tz = pendulum.timezone("Asia/Shanghai") + dt = datetime(1991, 4, 20, 1, 49, 8, fold=0) + dt = tz.convert(dt) + + epoch = datetime(1970, 1, 1, tzinfo=timezone("UTC")) + expected = (dt - epoch).total_seconds() + assert expected == 672079748.0 + + +@pytest.mark.skip( + reason="zoneinfo does not currently support POSIX transition rules to go beyond the last fixed transition." +) +def test_timezones_are_extended(): + tz = pendulum.timezone("Europe/Paris") + dt = tz.convert(pendulum.naive(2134, 2, 13, 1)) + + assert_datetime(dt, 2134, 2, 13, 1) + assert dt.utcoffset().total_seconds() == 3600 + assert dt.dst() == timedelta() + + dt = tz.convert(pendulum.naive(2134, 3, 28, 2, 30)) + + assert_datetime(dt, 2134, 3, 28, 3, 30) + assert dt.utcoffset().total_seconds() == 7200 + assert dt.dst() == timedelta(seconds=3600) + + dt = tz.convert(pendulum.naive(2134, 7, 11, 2, 30)) + + assert_datetime(dt, 2134, 7, 11, 2, 30) + assert dt.utcoffset().total_seconds() == 7200 + assert dt.dst() == timedelta(seconds=3600) + + dt = tz.convert(pendulum.naive(2134, 10, 31, 2, 30, fold=0)) + + assert_datetime(dt, 2134, 10, 31, 2, 30) + assert dt.utcoffset().total_seconds() == 7200 + assert dt.dst() == timedelta(seconds=3600) + + dt = tz.convert(pendulum.naive(2134, 10, 31, 2, 30)) + + assert_datetime(dt, 2134, 10, 31, 2, 30) + assert dt.utcoffset().total_seconds() == 3600 + assert dt.dst() == timedelta() + + +def test_repr(): + tz = timezone("Europe/Paris") + + assert repr(tz) == "Timezone('Europe/Paris')" diff --git a/tests/tz/test_timezones.py b/tests/tz/test_timezones.py new file mode 100644 index 0000000..200ed09 --- /dev/null +++ b/tests/tz/test_timezones.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +import pytest + +import pendulum + + +def test_timezones(): + zones = pendulum.timezones() + + assert "America/Argentina/Buenos_Aires" in zones + + +@pytest.mark.parametrize("zone", list(pendulum.timezones())) +def test_timezones_are_loadable(zone): + pendulum.timezone(zone) -- cgit v1.2.3