|
1 | 1 | from __future__ import annotations
|
2 | 2 |
|
| 3 | +import warnings |
3 | 4 | from itertools import product
|
4 | 5 | from typing import Callable, Literal
|
5 | 6 |
|
|
24 | 25 | Tick,
|
25 | 26 | YearBegin,
|
26 | 27 | YearEnd,
|
27 |
| - _days_in_month, |
28 | 28 | _legacy_to_new_freq,
|
29 | 29 | _new_to_legacy_freq,
|
30 | 30 | cftime_range,
|
@@ -589,22 +589,6 @@ def test_minus_offset_error(a, b):
|
589 | 589 | b - a
|
590 | 590 |
|
591 | 591 |
|
592 |
| -def test_days_in_month_non_december(calendar): |
593 |
| - date_type = get_date_type(calendar) |
594 |
| - reference = date_type(1, 4, 1) |
595 |
| - assert _days_in_month(reference) == 30 |
596 |
| - |
597 |
| - |
598 |
| -def test_days_in_month_december(calendar): |
599 |
| - if calendar == "360_day": |
600 |
| - expected = 30 |
601 |
| - else: |
602 |
| - expected = 31 |
603 |
| - date_type = get_date_type(calendar) |
604 |
| - reference = date_type(1, 12, 5) |
605 |
| - assert _days_in_month(reference) == expected |
606 |
| - |
607 |
| - |
608 | 592 | @pytest.mark.parametrize(
|
609 | 593 | ("initial_date_args", "offset", "expected_date_args"),
|
610 | 594 | [
|
@@ -657,7 +641,7 @@ def test_add_month_end(
|
657 | 641 |
|
658 | 642 | # Here the days at the end of each month varies based on the calendar used
|
659 | 643 | expected_date_args = (
|
660 |
| - expected_year_month + (_days_in_month(reference),) + expected_sub_day |
| 644 | + expected_year_month + (reference.daysinmonth,) + expected_sub_day |
661 | 645 | )
|
662 | 646 | expected = date_type(*expected_date_args)
|
663 | 647 | assert result == expected
|
@@ -694,17 +678,15 @@ def test_add_month_end_onOffset(
|
694 | 678 | date_type = get_date_type(calendar)
|
695 | 679 | reference_args = initial_year_month + (1,)
|
696 | 680 | reference = date_type(*reference_args)
|
697 |
| - initial_date_args = ( |
698 |
| - initial_year_month + (_days_in_month(reference),) + initial_sub_day |
699 |
| - ) |
| 681 | + initial_date_args = initial_year_month + (reference.daysinmonth,) + initial_sub_day |
700 | 682 | initial = date_type(*initial_date_args)
|
701 | 683 | result = initial + offset
|
702 | 684 | reference_args = expected_year_month + (1,)
|
703 | 685 | reference = date_type(*reference_args)
|
704 | 686 |
|
705 | 687 | # Here the days at the end of each month varies based on the calendar used
|
706 | 688 | expected_date_args = (
|
707 |
| - expected_year_month + (_days_in_month(reference),) + expected_sub_day |
| 689 | + expected_year_month + (reference.daysinmonth,) + expected_sub_day |
708 | 690 | )
|
709 | 691 | expected = date_type(*expected_date_args)
|
710 | 692 | assert result == expected
|
@@ -756,7 +738,7 @@ def test_add_year_end(
|
756 | 738 |
|
757 | 739 | # Here the days at the end of each month varies based on the calendar used
|
758 | 740 | expected_date_args = (
|
759 |
| - expected_year_month + (_days_in_month(reference),) + expected_sub_day |
| 741 | + expected_year_month + (reference.daysinmonth,) + expected_sub_day |
760 | 742 | )
|
761 | 743 | expected = date_type(*expected_date_args)
|
762 | 744 | assert result == expected
|
@@ -792,17 +774,15 @@ def test_add_year_end_onOffset(
|
792 | 774 | date_type = get_date_type(calendar)
|
793 | 775 | reference_args = initial_year_month + (1,)
|
794 | 776 | reference = date_type(*reference_args)
|
795 |
| - initial_date_args = ( |
796 |
| - initial_year_month + (_days_in_month(reference),) + initial_sub_day |
797 |
| - ) |
| 777 | + initial_date_args = initial_year_month + (reference.daysinmonth,) + initial_sub_day |
798 | 778 | initial = date_type(*initial_date_args)
|
799 | 779 | result = initial + offset
|
800 | 780 | reference_args = expected_year_month + (1,)
|
801 | 781 | reference = date_type(*reference_args)
|
802 | 782 |
|
803 | 783 | # Here the days at the end of each month varies based on the calendar used
|
804 | 784 | expected_date_args = (
|
805 |
| - expected_year_month + (_days_in_month(reference),) + expected_sub_day |
| 785 | + expected_year_month + (reference.daysinmonth,) + expected_sub_day |
806 | 786 | )
|
807 | 787 | expected = date_type(*expected_date_args)
|
808 | 788 | assert result == expected
|
@@ -854,7 +834,7 @@ def test_add_quarter_end(
|
854 | 834 |
|
855 | 835 | # Here the days at the end of each month varies based on the calendar used
|
856 | 836 | expected_date_args = (
|
857 |
| - expected_year_month + (_days_in_month(reference),) + expected_sub_day |
| 837 | + expected_year_month + (reference.daysinmonth,) + expected_sub_day |
858 | 838 | )
|
859 | 839 | expected = date_type(*expected_date_args)
|
860 | 840 | assert result == expected
|
@@ -890,17 +870,15 @@ def test_add_quarter_end_onOffset(
|
890 | 870 | date_type = get_date_type(calendar)
|
891 | 871 | reference_args = initial_year_month + (1,)
|
892 | 872 | reference = date_type(*reference_args)
|
893 |
| - initial_date_args = ( |
894 |
| - initial_year_month + (_days_in_month(reference),) + initial_sub_day |
895 |
| - ) |
| 873 | + initial_date_args = initial_year_month + (reference.daysinmonth,) + initial_sub_day |
896 | 874 | initial = date_type(*initial_date_args)
|
897 | 875 | result = initial + offset
|
898 | 876 | reference_args = expected_year_month + (1,)
|
899 | 877 | reference = date_type(*reference_args)
|
900 | 878 |
|
901 | 879 | # Here the days at the end of each month varies based on the calendar used
|
902 | 880 | expected_date_args = (
|
903 |
| - expected_year_month + (_days_in_month(reference),) + expected_sub_day |
| 881 | + expected_year_month + (reference.daysinmonth,) + expected_sub_day |
904 | 882 | )
|
905 | 883 | expected = date_type(*expected_date_args)
|
906 | 884 | assert result == expected
|
@@ -957,7 +935,7 @@ def test_onOffset_month_or_quarter_or_year_end(
|
957 | 935 | date_type = get_date_type(calendar)
|
958 | 936 | reference_args = year_month_args + (1,)
|
959 | 937 | reference = date_type(*reference_args)
|
960 |
| - date_args = year_month_args + (_days_in_month(reference),) + sub_day_args |
| 938 | + date_args = year_month_args + (reference.daysinmonth,) + sub_day_args |
961 | 939 | date = date_type(*date_args)
|
962 | 940 | result = offset.onOffset(date)
|
963 | 941 | assert result
|
@@ -1005,7 +983,7 @@ def test_rollforward(calendar, offset, initial_date_args, partial_expected_date_
|
1005 | 983 | elif isinstance(offset, (MonthEnd, QuarterEnd, YearEnd)):
|
1006 | 984 | reference_args = partial_expected_date_args + (1,)
|
1007 | 985 | reference = date_type(*reference_args)
|
1008 |
| - expected_date_args = partial_expected_date_args + (_days_in_month(reference),) |
| 986 | + expected_date_args = partial_expected_date_args + (reference.daysinmonth,) |
1009 | 987 | else:
|
1010 | 988 | expected_date_args = partial_expected_date_args
|
1011 | 989 | expected = date_type(*expected_date_args)
|
@@ -1056,7 +1034,7 @@ def test_rollback(calendar, offset, initial_date_args, partial_expected_date_arg
|
1056 | 1034 | elif isinstance(offset, (MonthEnd, QuarterEnd, YearEnd)):
|
1057 | 1035 | reference_args = partial_expected_date_args + (1,)
|
1058 | 1036 | reference = date_type(*reference_args)
|
1059 |
| - expected_date_args = partial_expected_date_args + (_days_in_month(reference),) |
| 1037 | + expected_date_args = partial_expected_date_args + (reference.daysinmonth,) |
1060 | 1038 | else:
|
1061 | 1039 | expected_date_args = partial_expected_date_args
|
1062 | 1040 | expected = date_type(*expected_date_args)
|
@@ -1787,3 +1765,69 @@ def test_date_range_no_freq(start, end, periods):
|
1787 | 1765 | expected = pd.date_range(start=start, end=end, periods=periods)
|
1788 | 1766 |
|
1789 | 1767 | np.testing.assert_array_equal(result, expected)
|
| 1768 | + |
| 1769 | + |
| 1770 | +@pytest.mark.parametrize( |
| 1771 | + "offset", |
| 1772 | + [ |
| 1773 | + MonthBegin(n=1), |
| 1774 | + MonthEnd(n=1), |
| 1775 | + QuarterBegin(n=1), |
| 1776 | + QuarterEnd(n=1), |
| 1777 | + YearBegin(n=1), |
| 1778 | + YearEnd(n=1), |
| 1779 | + ], |
| 1780 | + ids=lambda x: f"{x}", |
| 1781 | +) |
| 1782 | +@pytest.mark.parametrize("has_year_zero", [False, True]) |
| 1783 | +def test_offset_addition_preserves_has_year_zero(offset, has_year_zero): |
| 1784 | + |
| 1785 | + with warnings.catch_warnings(): |
| 1786 | + warnings.filterwarnings("ignore", message="this date/calendar/year zero") |
| 1787 | + datetime = cftime.DatetimeGregorian(-1, 12, 31, has_year_zero=has_year_zero) |
| 1788 | + |
| 1789 | + result = datetime + offset |
| 1790 | + assert result.has_year_zero == datetime.has_year_zero |
| 1791 | + if has_year_zero: |
| 1792 | + assert result.year == 0 |
| 1793 | + else: |
| 1794 | + assert result.year == 1 |
| 1795 | + |
| 1796 | + |
| 1797 | +@pytest.mark.parametrize( |
| 1798 | + "offset", |
| 1799 | + [ |
| 1800 | + MonthBegin(n=1), |
| 1801 | + MonthEnd(n=1), |
| 1802 | + QuarterBegin(n=1), |
| 1803 | + QuarterEnd(n=1), |
| 1804 | + YearBegin(n=1), |
| 1805 | + YearEnd(n=1), |
| 1806 | + ], |
| 1807 | + ids=lambda x: f"{x}", |
| 1808 | +) |
| 1809 | +@pytest.mark.parametrize("has_year_zero", [False, True]) |
| 1810 | +def test_offset_subtraction_preserves_has_year_zero(offset, has_year_zero): |
| 1811 | + datetime = cftime.DatetimeGregorian(1, 1, 1, has_year_zero=has_year_zero) |
| 1812 | + result = datetime - offset |
| 1813 | + assert result.has_year_zero == datetime.has_year_zero |
| 1814 | + if has_year_zero: |
| 1815 | + assert result.year == 0 |
| 1816 | + else: |
| 1817 | + assert result.year == -1 |
| 1818 | + |
| 1819 | + |
| 1820 | +@pytest.mark.parametrize("has_year_zero", [False, True]) |
| 1821 | +def test_offset_day_option_end_accounts_for_has_year_zero(has_year_zero): |
| 1822 | + offset = MonthEnd(n=1) |
| 1823 | + |
| 1824 | + with warnings.catch_warnings(): |
| 1825 | + warnings.filterwarnings("ignore", message="this date/calendar/year zero") |
| 1826 | + datetime = cftime.DatetimeGregorian(-1, 1, 31, has_year_zero=has_year_zero) |
| 1827 | + |
| 1828 | + result = datetime + offset |
| 1829 | + assert result.has_year_zero == datetime.has_year_zero |
| 1830 | + if has_year_zero: |
| 1831 | + assert result.day == 28 |
| 1832 | + else: |
| 1833 | + assert result.day == 29 |
0 commit comments