| from ._common import NotAValue | |
| import calendar | |
| from datetime import datetime, date, timedelta | |
| import unittest | |
| import pytest | |
| from dateutil.relativedelta import relativedelta, MO, TU, WE, FR, SU | |
| class RelativeDeltaTest(unittest.TestCase): | |
| now = datetime(2003, 9, 17, 20, 54, 47, 282310) | |
| today = date(2003, 9, 17) | |
| def testInheritance(self): | |
| # Ensure that relativedelta is inheritance-friendly. | |
| class rdChildClass(relativedelta): | |
| pass | |
| ccRD = rdChildClass(years=1, months=1, days=1, leapdays=1, weeks=1, | |
| hours=1, minutes=1, seconds=1, microseconds=1) | |
| rd = relativedelta(years=1, months=1, days=1, leapdays=1, weeks=1, | |
| hours=1, minutes=1, seconds=1, microseconds=1) | |
| self.assertEqual(type(ccRD + rd), type(ccRD), | |
| msg='Addition does not inherit type.') | |
| self.assertEqual(type(ccRD - rd), type(ccRD), | |
| msg='Subtraction does not inherit type.') | |
| self.assertEqual(type(-ccRD), type(ccRD), | |
| msg='Negation does not inherit type.') | |
| self.assertEqual(type(ccRD * 5.0), type(ccRD), | |
| msg='Multiplication does not inherit type.') | |
| self.assertEqual(type(ccRD / 5.0), type(ccRD), | |
| msg='Division does not inherit type.') | |
| def testMonthEndMonthBeginning(self): | |
| self.assertEqual(relativedelta(datetime(2003, 1, 31, 23, 59, 59), | |
| datetime(2003, 3, 1, 0, 0, 0)), | |
| relativedelta(months=-1, seconds=-1)) | |
| self.assertEqual(relativedelta(datetime(2003, 3, 1, 0, 0, 0), | |
| datetime(2003, 1, 31, 23, 59, 59)), | |
| relativedelta(months=1, seconds=1)) | |
| def testMonthEndMonthBeginningLeapYear(self): | |
| self.assertEqual(relativedelta(datetime(2012, 1, 31, 23, 59, 59), | |
| datetime(2012, 3, 1, 0, 0, 0)), | |
| relativedelta(months=-1, seconds=-1)) | |
| self.assertEqual(relativedelta(datetime(2003, 3, 1, 0, 0, 0), | |
| datetime(2003, 1, 31, 23, 59, 59)), | |
| relativedelta(months=1, seconds=1)) | |
| def testNextMonth(self): | |
| self.assertEqual(self.now+relativedelta(months=+1), | |
| datetime(2003, 10, 17, 20, 54, 47, 282310)) | |
| def testNextMonthPlusOneWeek(self): | |
| self.assertEqual(self.now+relativedelta(months=+1, weeks=+1), | |
| datetime(2003, 10, 24, 20, 54, 47, 282310)) | |
| def testNextMonthPlusOneWeek10am(self): | |
| self.assertEqual(self.today + | |
| relativedelta(months=+1, weeks=+1, hour=10), | |
| datetime(2003, 10, 24, 10, 0)) | |
| def testNextMonthPlusOneWeek10amDiff(self): | |
| self.assertEqual(relativedelta(datetime(2003, 10, 24, 10, 0), | |
| self.today), | |
| relativedelta(months=+1, days=+7, hours=+10)) | |
| def testOneMonthBeforeOneYear(self): | |
| self.assertEqual(self.now+relativedelta(years=+1, months=-1), | |
| datetime(2004, 8, 17, 20, 54, 47, 282310)) | |
| def testMonthsOfDiffNumOfDays(self): | |
| self.assertEqual(date(2003, 1, 27)+relativedelta(months=+1), | |
| date(2003, 2, 27)) | |
| self.assertEqual(date(2003, 1, 31)+relativedelta(months=+1), | |
| date(2003, 2, 28)) | |
| self.assertEqual(date(2003, 1, 31)+relativedelta(months=+2), | |
| date(2003, 3, 31)) | |
| def testMonthsOfDiffNumOfDaysWithYears(self): | |
| self.assertEqual(date(2000, 2, 28)+relativedelta(years=+1), | |
| date(2001, 2, 28)) | |
| self.assertEqual(date(2000, 2, 29)+relativedelta(years=+1), | |
| date(2001, 2, 28)) | |
| self.assertEqual(date(1999, 2, 28)+relativedelta(years=+1), | |
| date(2000, 2, 28)) | |
| self.assertEqual(date(1999, 3, 1)+relativedelta(years=+1), | |
| date(2000, 3, 1)) | |
| self.assertEqual(date(1999, 3, 1)+relativedelta(years=+1), | |
| date(2000, 3, 1)) | |
| self.assertEqual(date(2001, 2, 28)+relativedelta(years=-1), | |
| date(2000, 2, 28)) | |
| self.assertEqual(date(2001, 3, 1)+relativedelta(years=-1), | |
| date(2000, 3, 1)) | |
| def testNextFriday(self): | |
| self.assertEqual(self.today+relativedelta(weekday=FR), | |
| date(2003, 9, 19)) | |
| def testNextFridayInt(self): | |
| self.assertEqual(self.today+relativedelta(weekday=calendar.FRIDAY), | |
| date(2003, 9, 19)) | |
| def testLastFridayInThisMonth(self): | |
| self.assertEqual(self.today+relativedelta(day=31, weekday=FR(-1)), | |
| date(2003, 9, 26)) | |
| def testLastDayOfFebruary(self): | |
| self.assertEqual(date(2021, 2, 1) + relativedelta(day=31), | |
| date(2021, 2, 28)) | |
| def testLastDayOfFebruaryLeapYear(self): | |
| self.assertEqual(date(2020, 2, 1) + relativedelta(day=31), | |
| date(2020, 2, 29)) | |
| def testNextWednesdayIsToday(self): | |
| self.assertEqual(self.today+relativedelta(weekday=WE), | |
| date(2003, 9, 17)) | |
| def testNextWednesdayNotToday(self): | |
| self.assertEqual(self.today+relativedelta(days=+1, weekday=WE), | |
| date(2003, 9, 24)) | |
| def testAddMoreThan12Months(self): | |
| self.assertEqual(date(2003, 12, 1) + relativedelta(months=+13), | |
| date(2005, 1, 1)) | |
| def testAddNegativeMonths(self): | |
| self.assertEqual(date(2003, 1, 1) + relativedelta(months=-2), | |
| date(2002, 11, 1)) | |
| def test15thISOYearWeek(self): | |
| self.assertEqual(date(2003, 1, 1) + | |
| relativedelta(day=4, weeks=+14, weekday=MO(-1)), | |
| date(2003, 4, 7)) | |
| def testMillenniumAge(self): | |
| self.assertEqual(relativedelta(self.now, date(2001, 1, 1)), | |
| relativedelta(years=+2, months=+8, days=+16, | |
| hours=+20, minutes=+54, seconds=+47, | |
| microseconds=+282310)) | |
| def testJohnAge(self): | |
| self.assertEqual(relativedelta(self.now, | |
| datetime(1978, 4, 5, 12, 0)), | |
| relativedelta(years=+25, months=+5, days=+12, | |
| hours=+8, minutes=+54, seconds=+47, | |
| microseconds=+282310)) | |
| def testJohnAgeWithDate(self): | |
| self.assertEqual(relativedelta(self.today, | |
| datetime(1978, 4, 5, 12, 0)), | |
| relativedelta(years=+25, months=+5, days=+11, | |
| hours=+12)) | |
| def testYearDay(self): | |
| self.assertEqual(date(2003, 1, 1)+relativedelta(yearday=260), | |
| date(2003, 9, 17)) | |
| self.assertEqual(date(2002, 1, 1)+relativedelta(yearday=260), | |
| date(2002, 9, 17)) | |
| self.assertEqual(date(2000, 1, 1)+relativedelta(yearday=260), | |
| date(2000, 9, 16)) | |
| self.assertEqual(self.today+relativedelta(yearday=261), | |
| date(2003, 9, 18)) | |
| def testYearDayBug(self): | |
| # Tests a problem reported by Adam Ryan. | |
| self.assertEqual(date(2010, 1, 1)+relativedelta(yearday=15), | |
| date(2010, 1, 15)) | |
| def testNonLeapYearDay(self): | |
| self.assertEqual(date(2003, 1, 1)+relativedelta(nlyearday=260), | |
| date(2003, 9, 17)) | |
| self.assertEqual(date(2002, 1, 1)+relativedelta(nlyearday=260), | |
| date(2002, 9, 17)) | |
| self.assertEqual(date(2000, 1, 1)+relativedelta(nlyearday=260), | |
| date(2000, 9, 17)) | |
| self.assertEqual(self.today+relativedelta(yearday=261), | |
| date(2003, 9, 18)) | |
| def testAddition(self): | |
| self.assertEqual(relativedelta(days=10) + | |
| relativedelta(years=1, months=2, days=3, hours=4, | |
| minutes=5, microseconds=6), | |
| relativedelta(years=1, months=2, days=13, hours=4, | |
| minutes=5, microseconds=6)) | |
| def testAbsoluteAddition(self): | |
| self.assertEqual(relativedelta() + relativedelta(day=0, hour=0), | |
| relativedelta(day=0, hour=0)) | |
| self.assertEqual(relativedelta(day=0, hour=0) + relativedelta(), | |
| relativedelta(day=0, hour=0)) | |
| def testAdditionToDatetime(self): | |
| self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=1), | |
| datetime(2000, 1, 2)) | |
| def testRightAdditionToDatetime(self): | |
| self.assertEqual(relativedelta(days=1) + datetime(2000, 1, 1), | |
| datetime(2000, 1, 2)) | |
| def testAdditionInvalidType(self): | |
| with self.assertRaises(TypeError): | |
| relativedelta(days=3) + 9 | |
| def testAdditionUnsupportedType(self): | |
| # For unsupported types that define their own comparators, etc. | |
| self.assertIs(relativedelta(days=1) + NotAValue, NotAValue) | |
| def testAdditionFloatValue(self): | |
| self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=float(1)), | |
| datetime(2000, 1, 2)) | |
| self.assertEqual(datetime(2000, 1, 1) + relativedelta(months=float(1)), | |
| datetime(2000, 2, 1)) | |
| self.assertEqual(datetime(2000, 1, 1) + relativedelta(years=float(1)), | |
| datetime(2001, 1, 1)) | |
| def testAdditionFloatFractionals(self): | |
| self.assertEqual( | |
| datetime(2000, 1, 1, 0) + relativedelta(days=0.5), | |
| datetime(2000, 1, 1, 12), | |
| ) | |
| self.assertEqual( | |
| datetime(2000, 1, 1, 0, 0) + relativedelta(hours=0.5), | |
| datetime(2000, 1, 1, 0, 30), | |
| ) | |
| self.assertEqual( | |
| datetime(2000, 1, 1, 0, 0, 0) + relativedelta(minutes=0.5), | |
| datetime(2000, 1, 1, 0, 0, 30), | |
| ) | |
| self.assertEqual( | |
| datetime(2000, 1, 1, 0, 0, 0, 0) + relativedelta(seconds=0.5), | |
| datetime(2000, 1, 1, 0, 0, 0, 500000), | |
| ) | |
| self.assertEqual( | |
| datetime(2000, 1, 1, 0, 0, 0, 0) | |
| + relativedelta(microseconds=500000.25), | |
| datetime(2000, 1, 1, 0, 0, 0, 500000), | |
| ) | |
| def testSubtraction(self): | |
| self.assertEqual(relativedelta(days=10) - | |
| relativedelta(years=1, months=2, days=3, hours=4, | |
| minutes=5, microseconds=6), | |
| relativedelta(years=-1, months=-2, days=7, hours=-4, | |
| minutes=-5, microseconds=-6)) | |
| def testRightSubtractionFromDatetime(self): | |
| self.assertEqual(datetime(2000, 1, 2) - relativedelta(days=1), | |
| datetime(2000, 1, 1)) | |
| def testSubractionWithDatetime(self): | |
| self.assertRaises(TypeError, lambda x, y: x - y, | |
| (relativedelta(days=1), datetime(2000, 1, 1))) | |
| def testSubtractionInvalidType(self): | |
| with self.assertRaises(TypeError): | |
| relativedelta(hours=12) - 14 | |
| def testSubtractionUnsupportedType(self): | |
| self.assertIs(relativedelta(days=1) + NotAValue, NotAValue) | |
| def testMultiplication(self): | |
| self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=1) * 28, | |
| datetime(2000, 1, 29)) | |
| self.assertEqual(datetime(2000, 1, 1) + 28 * relativedelta(days=1), | |
| datetime(2000, 1, 29)) | |
| def testMultiplicationUnsupportedType(self): | |
| self.assertIs(relativedelta(days=1) * NotAValue, NotAValue) | |
| def testDivision(self): | |
| self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=28) / 28, | |
| datetime(2000, 1, 2)) | |
| def testDivisionUnsupportedType(self): | |
| self.assertIs(relativedelta(days=1) / NotAValue, NotAValue) | |
| def testBoolean(self): | |
| self.assertFalse(relativedelta(days=0)) | |
| self.assertTrue(relativedelta(days=1)) | |
| def testAbsoluteValueNegative(self): | |
| rd_base = relativedelta(years=-1, months=-5, days=-2, hours=-3, | |
| minutes=-5, seconds=-2, microseconds=-12) | |
| rd_expected = relativedelta(years=1, months=5, days=2, hours=3, | |
| minutes=5, seconds=2, microseconds=12) | |
| self.assertEqual(abs(rd_base), rd_expected) | |
| def testAbsoluteValuePositive(self): | |
| rd_base = relativedelta(years=1, months=5, days=2, hours=3, | |
| minutes=5, seconds=2, microseconds=12) | |
| rd_expected = rd_base | |
| self.assertEqual(abs(rd_base), rd_expected) | |
| def testComparison(self): | |
| d1 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1, | |
| minutes=1, seconds=1, microseconds=1) | |
| d2 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1, | |
| minutes=1, seconds=1, microseconds=1) | |
| d3 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1, | |
| minutes=1, seconds=1, microseconds=2) | |
| self.assertEqual(d1, d2) | |
| self.assertNotEqual(d1, d3) | |
| def testInequalityTypeMismatch(self): | |
| # Different type | |
| self.assertFalse(relativedelta(year=1) == 19) | |
| self.assertTrue(relativedelta(year=1) != 19) | |
| def testInequalityNoneType(self): | |
| self.assertFalse(relativedelta(year=1) == None) | |
| self.assertTrue(relativedelta(year=1) != None) | |
| def testInequalityUnsupportedType(self): | |
| self.assertIs(relativedelta(hours=3) == NotAValue, NotAValue) | |
| def testInequalityWeekdays(self): | |
| # Different weekdays | |
| no_wday = relativedelta(year=1997, month=4) | |
| wday_mo_1 = relativedelta(year=1997, month=4, weekday=MO(+1)) | |
| wday_mo_2 = relativedelta(year=1997, month=4, weekday=MO(+2)) | |
| wday_tu = relativedelta(year=1997, month=4, weekday=TU) | |
| self.assertTrue(wday_mo_1 == wday_mo_1) | |
| self.assertFalse(no_wday == wday_mo_1) | |
| self.assertFalse(wday_mo_1 == no_wday) | |
| self.assertFalse(wday_mo_1 == wday_mo_2) | |
| self.assertFalse(wday_mo_2 == wday_mo_1) | |
| self.assertFalse(wday_mo_1 == wday_tu) | |
| self.assertFalse(wday_tu == wday_mo_1) | |
| def testMonthOverflow(self): | |
| self.assertEqual(relativedelta(months=273), | |
| relativedelta(years=22, months=9)) | |
| def testWeeks(self): | |
| # Test that the weeks property is working properly. | |
| rd = relativedelta(years=4, months=2, weeks=8, days=6) | |
| self.assertEqual((rd.weeks, rd.days), (8, 8 * 7 + 6)) | |
| rd.weeks = 3 | |
| self.assertEqual((rd.weeks, rd.days), (3, 3 * 7 + 6)) | |
| def testRelativeDeltaRepr(self): | |
| self.assertEqual(repr(relativedelta(years=1, months=-1, days=15)), | |
| 'relativedelta(years=+1, months=-1, days=+15)') | |
| self.assertEqual(repr(relativedelta(months=14, seconds=-25)), | |
| 'relativedelta(years=+1, months=+2, seconds=-25)') | |
| self.assertEqual(repr(relativedelta(month=3, hour=3, weekday=SU(3))), | |
| 'relativedelta(month=3, weekday=SU(+3), hour=3)') | |
| def testRelativeDeltaFractionalYear(self): | |
| with self.assertRaises(ValueError): | |
| relativedelta(years=1.5) | |
| def testRelativeDeltaFractionalMonth(self): | |
| with self.assertRaises(ValueError): | |
| relativedelta(months=1.5) | |
| def testRelativeDeltaInvalidDatetimeObject(self): | |
| with self.assertRaises(TypeError): | |
| relativedelta(dt1='2018-01-01', dt2='2018-01-02') | |
| with self.assertRaises(TypeError): | |
| relativedelta(dt1=datetime(2018, 1, 1), dt2='2018-01-02') | |
| with self.assertRaises(TypeError): | |
| relativedelta(dt1='2018-01-01', dt2=datetime(2018, 1, 2)) | |
| def testRelativeDeltaFractionalAbsolutes(self): | |
| # Fractional absolute values will soon be unsupported, | |
| # check for the deprecation warning. | |
| with pytest.warns(DeprecationWarning): | |
| relativedelta(year=2.86) | |
| with pytest.warns(DeprecationWarning): | |
| relativedelta(month=1.29) | |
| with pytest.warns(DeprecationWarning): | |
| relativedelta(day=0.44) | |
| with pytest.warns(DeprecationWarning): | |
| relativedelta(hour=23.98) | |
| with pytest.warns(DeprecationWarning): | |
| relativedelta(minute=45.21) | |
| with pytest.warns(DeprecationWarning): | |
| relativedelta(second=13.2) | |
| with pytest.warns(DeprecationWarning): | |
| relativedelta(microsecond=157221.93) | |
| def testRelativeDeltaFractionalRepr(self): | |
| rd = relativedelta(years=3, months=-2, days=1.25) | |
| self.assertEqual(repr(rd), | |
| 'relativedelta(years=+3, months=-2, days=+1.25)') | |
| rd = relativedelta(hours=0.5, seconds=9.22) | |
| self.assertEqual(repr(rd), | |
| 'relativedelta(hours=+0.5, seconds=+9.22)') | |
| def testRelativeDeltaFractionalWeeks(self): | |
| # Equivalent to days=8, hours=18 | |
| rd = relativedelta(weeks=1.25) | |
| d1 = datetime(2009, 9, 3, 0, 0) | |
| self.assertEqual(d1 + rd, | |
| datetime(2009, 9, 11, 18)) | |
| def testRelativeDeltaFractionalDays(self): | |
| rd1 = relativedelta(days=1.48) | |
| d1 = datetime(2009, 9, 3, 0, 0) | |
| self.assertEqual(d1 + rd1, | |
| datetime(2009, 9, 4, 11, 31, 12)) | |
| rd2 = relativedelta(days=1.5) | |
| self.assertEqual(d1 + rd2, | |
| datetime(2009, 9, 4, 12, 0, 0)) | |
| def testRelativeDeltaFractionalHours(self): | |
| rd = relativedelta(days=1, hours=12.5) | |
| d1 = datetime(2009, 9, 3, 0, 0) | |
| self.assertEqual(d1 + rd, | |
| datetime(2009, 9, 4, 12, 30, 0)) | |
| def testRelativeDeltaFractionalMinutes(self): | |
| rd = relativedelta(hours=1, minutes=30.5) | |
| d1 = datetime(2009, 9, 3, 0, 0) | |
| self.assertEqual(d1 + rd, | |
| datetime(2009, 9, 3, 1, 30, 30)) | |
| def testRelativeDeltaFractionalSeconds(self): | |
| rd = relativedelta(hours=5, minutes=30, seconds=30.5) | |
| d1 = datetime(2009, 9, 3, 0, 0) | |
| self.assertEqual(d1 + rd, | |
| datetime(2009, 9, 3, 5, 30, 30, 500000)) | |
| def testRelativeDeltaFractionalPositiveOverflow(self): | |
| # Equivalent to (days=1, hours=14) | |
| rd1 = relativedelta(days=1.5, hours=2) | |
| d1 = datetime(2009, 9, 3, 0, 0) | |
| self.assertEqual(d1 + rd1, | |
| datetime(2009, 9, 4, 14, 0, 0)) | |
| # Equivalent to (days=1, hours=14, minutes=45) | |
| rd2 = relativedelta(days=1.5, hours=2.5, minutes=15) | |
| d1 = datetime(2009, 9, 3, 0, 0) | |
| self.assertEqual(d1 + rd2, | |
| datetime(2009, 9, 4, 14, 45)) | |
| # Carry back up - equivalent to (days=2, hours=2, minutes=0, seconds=1) | |
| rd3 = relativedelta(days=1.5, hours=13, minutes=59.5, seconds=31) | |
| self.assertEqual(d1 + rd3, | |
| datetime(2009, 9, 5, 2, 0, 1)) | |
| def testRelativeDeltaFractionalNegativeDays(self): | |
| # Equivalent to (days=-1, hours=-1) | |
| rd1 = relativedelta(days=-1.5, hours=11) | |
| d1 = datetime(2009, 9, 3, 12, 0) | |
| self.assertEqual(d1 + rd1, | |
| datetime(2009, 9, 2, 11, 0, 0)) | |
| # Equivalent to (days=-1, hours=-9) | |
| rd2 = relativedelta(days=-1.25, hours=-3) | |
| self.assertEqual(d1 + rd2, | |
| datetime(2009, 9, 2, 3)) | |
| def testRelativeDeltaNormalizeFractionalDays(self): | |
| # Equivalent to (days=2, hours=18) | |
| rd1 = relativedelta(days=2.75) | |
| self.assertEqual(rd1.normalized(), relativedelta(days=2, hours=18)) | |
| # Equivalent to (days=1, hours=11, minutes=31, seconds=12) | |
| rd2 = relativedelta(days=1.48) | |
| self.assertEqual(rd2.normalized(), | |
| relativedelta(days=1, hours=11, minutes=31, seconds=12)) | |
| def testRelativeDeltaNormalizeFractionalDays2(self): | |
| # Equivalent to (hours=1, minutes=30) | |
| rd1 = relativedelta(hours=1.5) | |
| self.assertEqual(rd1.normalized(), relativedelta(hours=1, minutes=30)) | |
| # Equivalent to (hours=3, minutes=17, seconds=5, microseconds=100) | |
| rd2 = relativedelta(hours=3.28472225) | |
| self.assertEqual(rd2.normalized(), | |
| relativedelta(hours=3, minutes=17, seconds=5, microseconds=100)) | |
| def testRelativeDeltaNormalizeFractionalMinutes(self): | |
| # Equivalent to (minutes=15, seconds=36) | |
| rd1 = relativedelta(minutes=15.6) | |
| self.assertEqual(rd1.normalized(), | |
| relativedelta(minutes=15, seconds=36)) | |
| # Equivalent to (minutes=25, seconds=20, microseconds=25000) | |
| rd2 = relativedelta(minutes=25.33375) | |
| self.assertEqual(rd2.normalized(), | |
| relativedelta(minutes=25, seconds=20, microseconds=25000)) | |
| def testRelativeDeltaNormalizeFractionalSeconds(self): | |
| # Equivalent to (seconds=45, microseconds=25000) | |
| rd1 = relativedelta(seconds=45.025) | |
| self.assertEqual(rd1.normalized(), | |
| relativedelta(seconds=45, microseconds=25000)) | |
| def testRelativeDeltaFractionalPositiveOverflow2(self): | |
| # Equivalent to (days=1, hours=14) | |
| rd1 = relativedelta(days=1.5, hours=2) | |
| self.assertEqual(rd1.normalized(), | |
| relativedelta(days=1, hours=14)) | |
| # Equivalent to (days=1, hours=14, minutes=45) | |
| rd2 = relativedelta(days=1.5, hours=2.5, minutes=15) | |
| self.assertEqual(rd2.normalized(), | |
| relativedelta(days=1, hours=14, minutes=45)) | |
| # Carry back up - equivalent to: | |
| # (days=2, hours=2, minutes=0, seconds=2, microseconds=3) | |
| rd3 = relativedelta(days=1.5, hours=13, minutes=59.50045, | |
| seconds=31.473, microseconds=500003) | |
| self.assertEqual(rd3.normalized(), | |
| relativedelta(days=2, hours=2, minutes=0, | |
| seconds=2, microseconds=3)) | |
| def testRelativeDeltaFractionalNegativeOverflow(self): | |
| # Equivalent to (days=-1) | |
| rd1 = relativedelta(days=-0.5, hours=-12) | |
| self.assertEqual(rd1.normalized(), | |
| relativedelta(days=-1)) | |
| # Equivalent to (days=-1) | |
| rd2 = relativedelta(days=-1.5, hours=12) | |
| self.assertEqual(rd2.normalized(), | |
| relativedelta(days=-1)) | |
| # Equivalent to (days=-1, hours=-14, minutes=-45) | |
| rd3 = relativedelta(days=-1.5, hours=-2.5, minutes=-15) | |
| self.assertEqual(rd3.normalized(), | |
| relativedelta(days=-1, hours=-14, minutes=-45)) | |
| # Equivalent to (days=-1, hours=-14, minutes=+15) | |
| rd4 = relativedelta(days=-1.5, hours=-2.5, minutes=45) | |
| self.assertEqual(rd4.normalized(), | |
| relativedelta(days=-1, hours=-14, minutes=+15)) | |
| # Carry back up - equivalent to: | |
| # (days=-2, hours=-2, minutes=0, seconds=-2, microseconds=-3) | |
| rd3 = relativedelta(days=-1.5, hours=-13, minutes=-59.50045, | |
| seconds=-31.473, microseconds=-500003) | |
| self.assertEqual(rd3.normalized(), | |
| relativedelta(days=-2, hours=-2, minutes=0, | |
| seconds=-2, microseconds=-3)) | |
| def testInvalidYearDay(self): | |
| with self.assertRaises(ValueError): | |
| relativedelta(yearday=367) | |
| def testAddTimedeltaToUnpopulatedRelativedelta(self): | |
| td = timedelta( | |
| days=1, | |
| seconds=1, | |
| microseconds=1, | |
| milliseconds=1, | |
| minutes=1, | |
| hours=1, | |
| weeks=1 | |
| ) | |
| expected = relativedelta( | |
| weeks=1, | |
| days=1, | |
| hours=1, | |
| minutes=1, | |
| seconds=1, | |
| microseconds=1001 | |
| ) | |
| self.assertEqual(expected, relativedelta() + td) | |
| def testAddTimedeltaToPopulatedRelativeDelta(self): | |
| td = timedelta( | |
| days=1, | |
| seconds=1, | |
| microseconds=1, | |
| milliseconds=1, | |
| minutes=1, | |
| hours=1, | |
| weeks=1 | |
| ) | |
| rd = relativedelta( | |
| year=1, | |
| month=1, | |
| day=1, | |
| hour=1, | |
| minute=1, | |
| second=1, | |
| microsecond=1, | |
| years=1, | |
| months=1, | |
| days=1, | |
| weeks=1, | |
| hours=1, | |
| minutes=1, | |
| seconds=1, | |
| microseconds=1 | |
| ) | |
| expected = relativedelta( | |
| year=1, | |
| month=1, | |
| day=1, | |
| hour=1, | |
| minute=1, | |
| second=1, | |
| microsecond=1, | |
| years=1, | |
| months=1, | |
| weeks=2, | |
| days=2, | |
| hours=2, | |
| minutes=2, | |
| seconds=2, | |
| microseconds=1002, | |
| ) | |
| self.assertEqual(expected, rd + td) | |
| def testHashable(self): | |
| try: | |
| {relativedelta(minute=1): 'test'} | |
| except: | |
| self.fail("relativedelta() failed to hash!") | |
| def testDayOfMonthPlus(self): | |
| assert [ | |
| date(2021, 1, 28) + relativedelta(months=1), | |
| date(2021, 2, 27) + relativedelta(months=1), | |
| date(2021, 4, 29) + relativedelta(months=1), | |
| date(2021, 5, 30) + relativedelta(months=1), | |
| ] == [ | |
| date(2021, 2, 28), | |
| date(2021, 3, 27), | |
| date(2021, 5, 29), | |
| date(2021, 6, 30), | |
| ] | |
| def testLastDayOfMonthPlus(self): | |
| assert [ | |
| date(2021, 1, 31) + relativedelta(months=1), | |
| date(2021, 1, 30) + relativedelta(months=1), | |
| date(2021, 1, 29) + relativedelta(months=1), | |
| date(2021, 1, 28) + relativedelta(months=1), | |
| date(2021, 2, 28) + relativedelta(months=1), | |
| date(2021, 4, 30) + relativedelta(months=1), | |
| date(2021, 5, 31) + relativedelta(months=1), | |
| ] == [ | |
| date(2021, 2, 28), | |
| date(2021, 2, 28), | |
| date(2021, 2, 28), | |
| date(2021, 2, 28), | |
| date(2021, 3, 28), | |
| date(2021, 5, 30), | |
| date(2021, 6, 30), | |
| ] | |
| def testDayOfMonthMinus(self): | |
| assert [ | |
| date(2021, 2, 27) - relativedelta(months=1), | |
| date(2021, 3, 30) - relativedelta(months=1), | |
| date(2021, 3, 29) - relativedelta(months=1), | |
| date(2021, 3, 28) - relativedelta(months=1), | |
| date(2021, 5, 30) - relativedelta(months=1), | |
| date(2021, 6, 29) - relativedelta(months=1), | |
| ] == [ | |
| date(2021, 1, 27), | |
| date(2021, 2, 28), | |
| date(2021, 2, 28), | |
| date(2021, 2, 28), | |
| date(2021, 4, 30), | |
| date(2021, 5, 29), | |
| ] | |
| def testLastDayOfMonthMinus(self): | |
| assert [ | |
| date(2021, 2, 28) - relativedelta(months=1), | |
| date(2021, 3, 31) - relativedelta(months=1), | |
| date(2021, 5, 31) - relativedelta(months=1), | |
| date(2021, 6, 30) - relativedelta(months=1), | |
| ] == [ | |
| date(2021, 1, 28), | |
| date(2021, 2, 28), | |
| date(2021, 4, 30), | |
| date(2021, 5, 30), | |
| ] | |
| @pytest.mark.parametrize("year", [1900, 2000, 2001, 2024]) | |
| def test_yearday_is_ordinal_day(year): | |
| first = date(year, 1, 1) | |
| days = range(1, 366 + calendar.isleap(year)) | |
| assert [first + relativedelta(yearday=n) for n in days] == [ | |
| first + timedelta(days=n - 1) for n in days | |
| ] | |
| class RelativeDeltaWeeksPropertyGetterTest(unittest.TestCase): | |
| """Test the weeks property getter""" | |
| def test_one_day(self): | |
| rd = relativedelta(days=1) | |
| self.assertEqual(rd.days, 1) | |
| self.assertEqual(rd.weeks, 0) | |
| def test_minus_one_day(self): | |
| rd = relativedelta(days=-1) | |
| self.assertEqual(rd.days, -1) | |
| self.assertEqual(rd.weeks, 0) | |
| def test_height_days(self): | |
| rd = relativedelta(days=8) | |
| self.assertEqual(rd.days, 8) | |
| self.assertEqual(rd.weeks, 1) | |
| def test_minus_height_days(self): | |
| rd = relativedelta(days=-8) | |
| self.assertEqual(rd.days, -8) | |
| self.assertEqual(rd.weeks, -1) | |
| class RelativeDeltaWeeksPropertySetterTest(unittest.TestCase): | |
| """Test the weeks setter which makes a "smart" update of the days attribute""" | |
| def test_one_day_set_one_week(self): | |
| rd = relativedelta(days=1) | |
| rd.weeks = 1 # add 7 days | |
| self.assertEqual(rd.days, 8) | |
| self.assertEqual(rd.weeks, 1) | |
| def test_minus_one_day_set_one_week(self): | |
| rd = relativedelta(days=-1) | |
| rd.weeks = 1 # add 7 days | |
| self.assertEqual(rd.days, 6) | |
| self.assertEqual(rd.weeks, 0) | |
| def test_height_days_set_minus_one_week(self): | |
| rd = relativedelta(days=8) | |
| rd.weeks = -1 # change from 1 week, 1 day to -1 week, 1 day | |
| self.assertEqual(rd.days, -6) | |
| self.assertEqual(rd.weeks, 0) | |
| def test_minus_height_days_set_minus_one_week(self): | |
| rd = relativedelta(days=-8) | |
| rd.weeks = -1 # does not change anything | |
| self.assertEqual(rd.days, -8) | |
| self.assertEqual(rd.weeks, -1) | |
| # vim:ts=4:sw=4:et |