test_relativedelta.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from ._common import NotAValue
  4. import calendar
  5. from datetime import datetime, date, timedelta
  6. import unittest
  7. import pytest
  8. from dateutil.relativedelta import relativedelta, MO, TU, WE, FR, SU
  9. class RelativeDeltaTest(unittest.TestCase):
  10. now = datetime(2003, 9, 17, 20, 54, 47, 282310)
  11. today = date(2003, 9, 17)
  12. def testInheritance(self):
  13. # Ensure that relativedelta is inheritance-friendly.
  14. class rdChildClass(relativedelta):
  15. pass
  16. ccRD = rdChildClass(years=1, months=1, days=1, leapdays=1, weeks=1,
  17. hours=1, minutes=1, seconds=1, microseconds=1)
  18. rd = relativedelta(years=1, months=1, days=1, leapdays=1, weeks=1,
  19. hours=1, minutes=1, seconds=1, microseconds=1)
  20. self.assertEqual(type(ccRD + rd), type(ccRD),
  21. msg='Addition does not inherit type.')
  22. self.assertEqual(type(ccRD - rd), type(ccRD),
  23. msg='Subtraction does not inherit type.')
  24. self.assertEqual(type(-ccRD), type(ccRD),
  25. msg='Negation does not inherit type.')
  26. self.assertEqual(type(ccRD * 5.0), type(ccRD),
  27. msg='Multiplication does not inherit type.')
  28. self.assertEqual(type(ccRD / 5.0), type(ccRD),
  29. msg='Division does not inherit type.')
  30. def testMonthEndMonthBeginning(self):
  31. self.assertEqual(relativedelta(datetime(2003, 1, 31, 23, 59, 59),
  32. datetime(2003, 3, 1, 0, 0, 0)),
  33. relativedelta(months=-1, seconds=-1))
  34. self.assertEqual(relativedelta(datetime(2003, 3, 1, 0, 0, 0),
  35. datetime(2003, 1, 31, 23, 59, 59)),
  36. relativedelta(months=1, seconds=1))
  37. def testMonthEndMonthBeginningLeapYear(self):
  38. self.assertEqual(relativedelta(datetime(2012, 1, 31, 23, 59, 59),
  39. datetime(2012, 3, 1, 0, 0, 0)),
  40. relativedelta(months=-1, seconds=-1))
  41. self.assertEqual(relativedelta(datetime(2003, 3, 1, 0, 0, 0),
  42. datetime(2003, 1, 31, 23, 59, 59)),
  43. relativedelta(months=1, seconds=1))
  44. def testNextMonth(self):
  45. self.assertEqual(self.now+relativedelta(months=+1),
  46. datetime(2003, 10, 17, 20, 54, 47, 282310))
  47. def testNextMonthPlusOneWeek(self):
  48. self.assertEqual(self.now+relativedelta(months=+1, weeks=+1),
  49. datetime(2003, 10, 24, 20, 54, 47, 282310))
  50. def testNextMonthPlusOneWeek10am(self):
  51. self.assertEqual(self.today +
  52. relativedelta(months=+1, weeks=+1, hour=10),
  53. datetime(2003, 10, 24, 10, 0))
  54. def testNextMonthPlusOneWeek10amDiff(self):
  55. self.assertEqual(relativedelta(datetime(2003, 10, 24, 10, 0),
  56. self.today),
  57. relativedelta(months=+1, days=+7, hours=+10))
  58. def testOneMonthBeforeOneYear(self):
  59. self.assertEqual(self.now+relativedelta(years=+1, months=-1),
  60. datetime(2004, 8, 17, 20, 54, 47, 282310))
  61. def testMonthsOfDiffNumOfDays(self):
  62. self.assertEqual(date(2003, 1, 27)+relativedelta(months=+1),
  63. date(2003, 2, 27))
  64. self.assertEqual(date(2003, 1, 31)+relativedelta(months=+1),
  65. date(2003, 2, 28))
  66. self.assertEqual(date(2003, 1, 31)+relativedelta(months=+2),
  67. date(2003, 3, 31))
  68. def testMonthsOfDiffNumOfDaysWithYears(self):
  69. self.assertEqual(date(2000, 2, 28)+relativedelta(years=+1),
  70. date(2001, 2, 28))
  71. self.assertEqual(date(2000, 2, 29)+relativedelta(years=+1),
  72. date(2001, 2, 28))
  73. self.assertEqual(date(1999, 2, 28)+relativedelta(years=+1),
  74. date(2000, 2, 28))
  75. self.assertEqual(date(1999, 3, 1)+relativedelta(years=+1),
  76. date(2000, 3, 1))
  77. self.assertEqual(date(1999, 3, 1)+relativedelta(years=+1),
  78. date(2000, 3, 1))
  79. self.assertEqual(date(2001, 2, 28)+relativedelta(years=-1),
  80. date(2000, 2, 28))
  81. self.assertEqual(date(2001, 3, 1)+relativedelta(years=-1),
  82. date(2000, 3, 1))
  83. def testNextFriday(self):
  84. self.assertEqual(self.today+relativedelta(weekday=FR),
  85. date(2003, 9, 19))
  86. def testNextFridayInt(self):
  87. self.assertEqual(self.today+relativedelta(weekday=calendar.FRIDAY),
  88. date(2003, 9, 19))
  89. def testLastFridayInThisMonth(self):
  90. self.assertEqual(self.today+relativedelta(day=31, weekday=FR(-1)),
  91. date(2003, 9, 26))
  92. def testLastDayOfFebruary(self):
  93. self.assertEqual(date(2021, 2, 1) + relativedelta(day=31),
  94. date(2021, 2, 28))
  95. def testLastDayOfFebruaryLeapYear(self):
  96. self.assertEqual(date(2020, 2, 1) + relativedelta(day=31),
  97. date(2020, 2, 29))
  98. def testNextWednesdayIsToday(self):
  99. self.assertEqual(self.today+relativedelta(weekday=WE),
  100. date(2003, 9, 17))
  101. def testNextWednesdayNotToday(self):
  102. self.assertEqual(self.today+relativedelta(days=+1, weekday=WE),
  103. date(2003, 9, 24))
  104. def testAddMoreThan12Months(self):
  105. self.assertEqual(date(2003, 12, 1) + relativedelta(months=+13),
  106. date(2005, 1, 1))
  107. def testAddNegativeMonths(self):
  108. self.assertEqual(date(2003, 1, 1) + relativedelta(months=-2),
  109. date(2002, 11, 1))
  110. def test15thISOYearWeek(self):
  111. self.assertEqual(date(2003, 1, 1) +
  112. relativedelta(day=4, weeks=+14, weekday=MO(-1)),
  113. date(2003, 4, 7))
  114. def testMillenniumAge(self):
  115. self.assertEqual(relativedelta(self.now, date(2001, 1, 1)),
  116. relativedelta(years=+2, months=+8, days=+16,
  117. hours=+20, minutes=+54, seconds=+47,
  118. microseconds=+282310))
  119. def testJohnAge(self):
  120. self.assertEqual(relativedelta(self.now,
  121. datetime(1978, 4, 5, 12, 0)),
  122. relativedelta(years=+25, months=+5, days=+12,
  123. hours=+8, minutes=+54, seconds=+47,
  124. microseconds=+282310))
  125. def testJohnAgeWithDate(self):
  126. self.assertEqual(relativedelta(self.today,
  127. datetime(1978, 4, 5, 12, 0)),
  128. relativedelta(years=+25, months=+5, days=+11,
  129. hours=+12))
  130. def testYearDay(self):
  131. self.assertEqual(date(2003, 1, 1)+relativedelta(yearday=260),
  132. date(2003, 9, 17))
  133. self.assertEqual(date(2002, 1, 1)+relativedelta(yearday=260),
  134. date(2002, 9, 17))
  135. self.assertEqual(date(2000, 1, 1)+relativedelta(yearday=260),
  136. date(2000, 9, 16))
  137. self.assertEqual(self.today+relativedelta(yearday=261),
  138. date(2003, 9, 18))
  139. def testYearDayBug(self):
  140. # Tests a problem reported by Adam Ryan.
  141. self.assertEqual(date(2010, 1, 1)+relativedelta(yearday=15),
  142. date(2010, 1, 15))
  143. def testNonLeapYearDay(self):
  144. self.assertEqual(date(2003, 1, 1)+relativedelta(nlyearday=260),
  145. date(2003, 9, 17))
  146. self.assertEqual(date(2002, 1, 1)+relativedelta(nlyearday=260),
  147. date(2002, 9, 17))
  148. self.assertEqual(date(2000, 1, 1)+relativedelta(nlyearday=260),
  149. date(2000, 9, 17))
  150. self.assertEqual(self.today+relativedelta(yearday=261),
  151. date(2003, 9, 18))
  152. def testAddition(self):
  153. self.assertEqual(relativedelta(days=10) +
  154. relativedelta(years=1, months=2, days=3, hours=4,
  155. minutes=5, microseconds=6),
  156. relativedelta(years=1, months=2, days=13, hours=4,
  157. minutes=5, microseconds=6))
  158. def testAbsoluteAddition(self):
  159. self.assertEqual(relativedelta() + relativedelta(day=0, hour=0),
  160. relativedelta(day=0, hour=0))
  161. self.assertEqual(relativedelta(day=0, hour=0) + relativedelta(),
  162. relativedelta(day=0, hour=0))
  163. def testAdditionToDatetime(self):
  164. self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=1),
  165. datetime(2000, 1, 2))
  166. def testRightAdditionToDatetime(self):
  167. self.assertEqual(relativedelta(days=1) + datetime(2000, 1, 1),
  168. datetime(2000, 1, 2))
  169. def testAdditionInvalidType(self):
  170. with self.assertRaises(TypeError):
  171. relativedelta(days=3) + 9
  172. def testAdditionUnsupportedType(self):
  173. # For unsupported types that define their own comparators, etc.
  174. self.assertIs(relativedelta(days=1) + NotAValue, NotAValue)
  175. def testAdditionFloatValue(self):
  176. self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=float(1)),
  177. datetime(2000, 1, 2))
  178. self.assertEqual(datetime(2000, 1, 1) + relativedelta(months=float(1)),
  179. datetime(2000, 2, 1))
  180. self.assertEqual(datetime(2000, 1, 1) + relativedelta(years=float(1)),
  181. datetime(2001, 1, 1))
  182. def testAdditionFloatFractionals(self):
  183. self.assertEqual(datetime(2000, 1, 1, 0) +
  184. relativedelta(days=float(0.5)),
  185. datetime(2000, 1, 1, 12))
  186. self.assertEqual(datetime(2000, 1, 1, 0, 0) +
  187. relativedelta(hours=float(0.5)),
  188. datetime(2000, 1, 1, 0, 30))
  189. self.assertEqual(datetime(2000, 1, 1, 0, 0, 0) +
  190. relativedelta(minutes=float(0.5)),
  191. datetime(2000, 1, 1, 0, 0, 30))
  192. self.assertEqual(datetime(2000, 1, 1, 0, 0, 0, 0) +
  193. relativedelta(seconds=float(0.5)),
  194. datetime(2000, 1, 1, 0, 0, 0, 500000))
  195. self.assertEqual(datetime(2000, 1, 1, 0, 0, 0, 0) +
  196. relativedelta(microseconds=float(500000.25)),
  197. datetime(2000, 1, 1, 0, 0, 0, 500000))
  198. def testSubtraction(self):
  199. self.assertEqual(relativedelta(days=10) -
  200. relativedelta(years=1, months=2, days=3, hours=4,
  201. minutes=5, microseconds=6),
  202. relativedelta(years=-1, months=-2, days=7, hours=-4,
  203. minutes=-5, microseconds=-6))
  204. def testRightSubtractionFromDatetime(self):
  205. self.assertEqual(datetime(2000, 1, 2) - relativedelta(days=1),
  206. datetime(2000, 1, 1))
  207. def testSubractionWithDatetime(self):
  208. self.assertRaises(TypeError, lambda x, y: x - y,
  209. (relativedelta(days=1), datetime(2000, 1, 1)))
  210. def testSubtractionInvalidType(self):
  211. with self.assertRaises(TypeError):
  212. relativedelta(hours=12) - 14
  213. def testSubtractionUnsupportedType(self):
  214. self.assertIs(relativedelta(days=1) + NotAValue, NotAValue)
  215. def testMultiplication(self):
  216. self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=1) * 28,
  217. datetime(2000, 1, 29))
  218. self.assertEqual(datetime(2000, 1, 1) + 28 * relativedelta(days=1),
  219. datetime(2000, 1, 29))
  220. def testMultiplicationUnsupportedType(self):
  221. self.assertIs(relativedelta(days=1) * NotAValue, NotAValue)
  222. def testDivision(self):
  223. self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=28) / 28,
  224. datetime(2000, 1, 2))
  225. def testDivisionUnsupportedType(self):
  226. self.assertIs(relativedelta(days=1) / NotAValue, NotAValue)
  227. def testBoolean(self):
  228. self.assertFalse(relativedelta(days=0))
  229. self.assertTrue(relativedelta(days=1))
  230. def testAbsoluteValueNegative(self):
  231. rd_base = relativedelta(years=-1, months=-5, days=-2, hours=-3,
  232. minutes=-5, seconds=-2, microseconds=-12)
  233. rd_expected = relativedelta(years=1, months=5, days=2, hours=3,
  234. minutes=5, seconds=2, microseconds=12)
  235. self.assertEqual(abs(rd_base), rd_expected)
  236. def testAbsoluteValuePositive(self):
  237. rd_base = relativedelta(years=1, months=5, days=2, hours=3,
  238. minutes=5, seconds=2, microseconds=12)
  239. rd_expected = rd_base
  240. self.assertEqual(abs(rd_base), rd_expected)
  241. def testComparison(self):
  242. d1 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1,
  243. minutes=1, seconds=1, microseconds=1)
  244. d2 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1,
  245. minutes=1, seconds=1, microseconds=1)
  246. d3 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1,
  247. minutes=1, seconds=1, microseconds=2)
  248. self.assertEqual(d1, d2)
  249. self.assertNotEqual(d1, d3)
  250. def testInequalityTypeMismatch(self):
  251. # Different type
  252. self.assertFalse(relativedelta(year=1) == 19)
  253. def testInequalityUnsupportedType(self):
  254. self.assertIs(relativedelta(hours=3) == NotAValue, NotAValue)
  255. def testInequalityWeekdays(self):
  256. # Different weekdays
  257. no_wday = relativedelta(year=1997, month=4)
  258. wday_mo_1 = relativedelta(year=1997, month=4, weekday=MO(+1))
  259. wday_mo_2 = relativedelta(year=1997, month=4, weekday=MO(+2))
  260. wday_tu = relativedelta(year=1997, month=4, weekday=TU)
  261. self.assertTrue(wday_mo_1 == wday_mo_1)
  262. self.assertFalse(no_wday == wday_mo_1)
  263. self.assertFalse(wday_mo_1 == no_wday)
  264. self.assertFalse(wday_mo_1 == wday_mo_2)
  265. self.assertFalse(wday_mo_2 == wday_mo_1)
  266. self.assertFalse(wday_mo_1 == wday_tu)
  267. self.assertFalse(wday_tu == wday_mo_1)
  268. def testMonthOverflow(self):
  269. self.assertEqual(relativedelta(months=273),
  270. relativedelta(years=22, months=9))
  271. def testWeeks(self):
  272. # Test that the weeks property is working properly.
  273. rd = relativedelta(years=4, months=2, weeks=8, days=6)
  274. self.assertEqual((rd.weeks, rd.days), (8, 8 * 7 + 6))
  275. rd.weeks = 3
  276. self.assertEqual((rd.weeks, rd.days), (3, 3 * 7 + 6))
  277. def testRelativeDeltaRepr(self):
  278. self.assertEqual(repr(relativedelta(years=1, months=-1, days=15)),
  279. 'relativedelta(years=+1, months=-1, days=+15)')
  280. self.assertEqual(repr(relativedelta(months=14, seconds=-25)),
  281. 'relativedelta(years=+1, months=+2, seconds=-25)')
  282. self.assertEqual(repr(relativedelta(month=3, hour=3, weekday=SU(3))),
  283. 'relativedelta(month=3, weekday=SU(+3), hour=3)')
  284. def testRelativeDeltaFractionalYear(self):
  285. with self.assertRaises(ValueError):
  286. relativedelta(years=1.5)
  287. def testRelativeDeltaFractionalMonth(self):
  288. with self.assertRaises(ValueError):
  289. relativedelta(months=1.5)
  290. def testRelativeDeltaInvalidDatetimeObject(self):
  291. with self.assertRaises(TypeError):
  292. relativedelta(dt1='2018-01-01', dt2='2018-01-02')
  293. with self.assertRaises(TypeError):
  294. relativedelta(dt1=datetime(2018, 1, 1), dt2='2018-01-02')
  295. with self.assertRaises(TypeError):
  296. relativedelta(dt1='2018-01-01', dt2=datetime(2018, 1, 2))
  297. def testRelativeDeltaFractionalAbsolutes(self):
  298. # Fractional absolute values will soon be unsupported,
  299. # check for the deprecation warning.
  300. with pytest.warns(DeprecationWarning):
  301. relativedelta(year=2.86)
  302. with pytest.warns(DeprecationWarning):
  303. relativedelta(month=1.29)
  304. with pytest.warns(DeprecationWarning):
  305. relativedelta(day=0.44)
  306. with pytest.warns(DeprecationWarning):
  307. relativedelta(hour=23.98)
  308. with pytest.warns(DeprecationWarning):
  309. relativedelta(minute=45.21)
  310. with pytest.warns(DeprecationWarning):
  311. relativedelta(second=13.2)
  312. with pytest.warns(DeprecationWarning):
  313. relativedelta(microsecond=157221.93)
  314. def testRelativeDeltaFractionalRepr(self):
  315. rd = relativedelta(years=3, months=-2, days=1.25)
  316. self.assertEqual(repr(rd),
  317. 'relativedelta(years=+3, months=-2, days=+1.25)')
  318. rd = relativedelta(hours=0.5, seconds=9.22)
  319. self.assertEqual(repr(rd),
  320. 'relativedelta(hours=+0.5, seconds=+9.22)')
  321. def testRelativeDeltaFractionalWeeks(self):
  322. # Equivalent to days=8, hours=18
  323. rd = relativedelta(weeks=1.25)
  324. d1 = datetime(2009, 9, 3, 0, 0)
  325. self.assertEqual(d1 + rd,
  326. datetime(2009, 9, 11, 18))
  327. def testRelativeDeltaFractionalDays(self):
  328. rd1 = relativedelta(days=1.48)
  329. d1 = datetime(2009, 9, 3, 0, 0)
  330. self.assertEqual(d1 + rd1,
  331. datetime(2009, 9, 4, 11, 31, 12))
  332. rd2 = relativedelta(days=1.5)
  333. self.assertEqual(d1 + rd2,
  334. datetime(2009, 9, 4, 12, 0, 0))
  335. def testRelativeDeltaFractionalHours(self):
  336. rd = relativedelta(days=1, hours=12.5)
  337. d1 = datetime(2009, 9, 3, 0, 0)
  338. self.assertEqual(d1 + rd,
  339. datetime(2009, 9, 4, 12, 30, 0))
  340. def testRelativeDeltaFractionalMinutes(self):
  341. rd = relativedelta(hours=1, minutes=30.5)
  342. d1 = datetime(2009, 9, 3, 0, 0)
  343. self.assertEqual(d1 + rd,
  344. datetime(2009, 9, 3, 1, 30, 30))
  345. def testRelativeDeltaFractionalSeconds(self):
  346. rd = relativedelta(hours=5, minutes=30, seconds=30.5)
  347. d1 = datetime(2009, 9, 3, 0, 0)
  348. self.assertEqual(d1 + rd,
  349. datetime(2009, 9, 3, 5, 30, 30, 500000))
  350. def testRelativeDeltaFractionalPositiveOverflow(self):
  351. # Equivalent to (days=1, hours=14)
  352. rd1 = relativedelta(days=1.5, hours=2)
  353. d1 = datetime(2009, 9, 3, 0, 0)
  354. self.assertEqual(d1 + rd1,
  355. datetime(2009, 9, 4, 14, 0, 0))
  356. # Equivalent to (days=1, hours=14, minutes=45)
  357. rd2 = relativedelta(days=1.5, hours=2.5, minutes=15)
  358. d1 = datetime(2009, 9, 3, 0, 0)
  359. self.assertEqual(d1 + rd2,
  360. datetime(2009, 9, 4, 14, 45))
  361. # Carry back up - equivalent to (days=2, hours=2, minutes=0, seconds=1)
  362. rd3 = relativedelta(days=1.5, hours=13, minutes=59.5, seconds=31)
  363. self.assertEqual(d1 + rd3,
  364. datetime(2009, 9, 5, 2, 0, 1))
  365. def testRelativeDeltaFractionalNegativeDays(self):
  366. # Equivalent to (days=-1, hours=-1)
  367. rd1 = relativedelta(days=-1.5, hours=11)
  368. d1 = datetime(2009, 9, 3, 12, 0)
  369. self.assertEqual(d1 + rd1,
  370. datetime(2009, 9, 2, 11, 0, 0))
  371. # Equivalent to (days=-1, hours=-9)
  372. rd2 = relativedelta(days=-1.25, hours=-3)
  373. self.assertEqual(d1 + rd2,
  374. datetime(2009, 9, 2, 3))
  375. def testRelativeDeltaNormalizeFractionalDays(self):
  376. # Equivalent to (days=2, hours=18)
  377. rd1 = relativedelta(days=2.75)
  378. self.assertEqual(rd1.normalized(), relativedelta(days=2, hours=18))
  379. # Equivalent to (days=1, hours=11, minutes=31, seconds=12)
  380. rd2 = relativedelta(days=1.48)
  381. self.assertEqual(rd2.normalized(),
  382. relativedelta(days=1, hours=11, minutes=31, seconds=12))
  383. def testRelativeDeltaNormalizeFractionalDays2(self):
  384. # Equivalent to (hours=1, minutes=30)
  385. rd1 = relativedelta(hours=1.5)
  386. self.assertEqual(rd1.normalized(), relativedelta(hours=1, minutes=30))
  387. # Equivalent to (hours=3, minutes=17, seconds=5, microseconds=100)
  388. rd2 = relativedelta(hours=3.28472225)
  389. self.assertEqual(rd2.normalized(),
  390. relativedelta(hours=3, minutes=17, seconds=5, microseconds=100))
  391. def testRelativeDeltaNormalizeFractionalMinutes(self):
  392. # Equivalent to (minutes=15, seconds=36)
  393. rd1 = relativedelta(minutes=15.6)
  394. self.assertEqual(rd1.normalized(),
  395. relativedelta(minutes=15, seconds=36))
  396. # Equivalent to (minutes=25, seconds=20, microseconds=25000)
  397. rd2 = relativedelta(minutes=25.33375)
  398. self.assertEqual(rd2.normalized(),
  399. relativedelta(minutes=25, seconds=20, microseconds=25000))
  400. def testRelativeDeltaNormalizeFractionalSeconds(self):
  401. # Equivalent to (seconds=45, microseconds=25000)
  402. rd1 = relativedelta(seconds=45.025)
  403. self.assertEqual(rd1.normalized(),
  404. relativedelta(seconds=45, microseconds=25000))
  405. def testRelativeDeltaFractionalPositiveOverflow2(self):
  406. # Equivalent to (days=1, hours=14)
  407. rd1 = relativedelta(days=1.5, hours=2)
  408. self.assertEqual(rd1.normalized(),
  409. relativedelta(days=1, hours=14))
  410. # Equivalent to (days=1, hours=14, minutes=45)
  411. rd2 = relativedelta(days=1.5, hours=2.5, minutes=15)
  412. self.assertEqual(rd2.normalized(),
  413. relativedelta(days=1, hours=14, minutes=45))
  414. # Carry back up - equivalent to:
  415. # (days=2, hours=2, minutes=0, seconds=2, microseconds=3)
  416. rd3 = relativedelta(days=1.5, hours=13, minutes=59.50045,
  417. seconds=31.473, microseconds=500003)
  418. self.assertEqual(rd3.normalized(),
  419. relativedelta(days=2, hours=2, minutes=0,
  420. seconds=2, microseconds=3))
  421. def testRelativeDeltaFractionalNegativeOverflow(self):
  422. # Equivalent to (days=-1)
  423. rd1 = relativedelta(days=-0.5, hours=-12)
  424. self.assertEqual(rd1.normalized(),
  425. relativedelta(days=-1))
  426. # Equivalent to (days=-1)
  427. rd2 = relativedelta(days=-1.5, hours=12)
  428. self.assertEqual(rd2.normalized(),
  429. relativedelta(days=-1))
  430. # Equivalent to (days=-1, hours=-14, minutes=-45)
  431. rd3 = relativedelta(days=-1.5, hours=-2.5, minutes=-15)
  432. self.assertEqual(rd3.normalized(),
  433. relativedelta(days=-1, hours=-14, minutes=-45))
  434. # Equivalent to (days=-1, hours=-14, minutes=+15)
  435. rd4 = relativedelta(days=-1.5, hours=-2.5, minutes=45)
  436. self.assertEqual(rd4.normalized(),
  437. relativedelta(days=-1, hours=-14, minutes=+15))
  438. # Carry back up - equivalent to:
  439. # (days=-2, hours=-2, minutes=0, seconds=-2, microseconds=-3)
  440. rd3 = relativedelta(days=-1.5, hours=-13, minutes=-59.50045,
  441. seconds=-31.473, microseconds=-500003)
  442. self.assertEqual(rd3.normalized(),
  443. relativedelta(days=-2, hours=-2, minutes=0,
  444. seconds=-2, microseconds=-3))
  445. def testInvalidYearDay(self):
  446. with self.assertRaises(ValueError):
  447. relativedelta(yearday=367)
  448. def testAddTimedeltaToUnpopulatedRelativedelta(self):
  449. td = timedelta(
  450. days=1,
  451. seconds=1,
  452. microseconds=1,
  453. milliseconds=1,
  454. minutes=1,
  455. hours=1,
  456. weeks=1
  457. )
  458. expected = relativedelta(
  459. weeks=1,
  460. days=1,
  461. hours=1,
  462. minutes=1,
  463. seconds=1,
  464. microseconds=1001
  465. )
  466. self.assertEqual(expected, relativedelta() + td)
  467. def testAddTimedeltaToPopulatedRelativeDelta(self):
  468. td = timedelta(
  469. days=1,
  470. seconds=1,
  471. microseconds=1,
  472. milliseconds=1,
  473. minutes=1,
  474. hours=1,
  475. weeks=1
  476. )
  477. rd = relativedelta(
  478. year=1,
  479. month=1,
  480. day=1,
  481. hour=1,
  482. minute=1,
  483. second=1,
  484. microsecond=1,
  485. years=1,
  486. months=1,
  487. days=1,
  488. weeks=1,
  489. hours=1,
  490. minutes=1,
  491. seconds=1,
  492. microseconds=1
  493. )
  494. expected = relativedelta(
  495. year=1,
  496. month=1,
  497. day=1,
  498. hour=1,
  499. minute=1,
  500. second=1,
  501. microsecond=1,
  502. years=1,
  503. months=1,
  504. weeks=2,
  505. days=2,
  506. hours=2,
  507. minutes=2,
  508. seconds=2,
  509. microseconds=1002,
  510. )
  511. self.assertEqual(expected, rd + td)
  512. def testHashable(self):
  513. try:
  514. {relativedelta(minute=1): 'test'}
  515. except:
  516. self.fail("relativedelta() failed to hash!")
  517. def testDayOfMonthPlus(self):
  518. assert [
  519. date(2021, 1, 28) + relativedelta(months=1),
  520. date(2021, 2, 27) + relativedelta(months=1),
  521. date(2021, 4, 29) + relativedelta(months=1),
  522. date(2021, 5, 30) + relativedelta(months=1),
  523. ] == [
  524. date(2021, 2, 28),
  525. date(2021, 3, 27),
  526. date(2021, 5, 29),
  527. date(2021, 6, 30),
  528. ]
  529. def testLastDayOfMonthPlus(self):
  530. assert [
  531. date(2021, 1, 31) + relativedelta(months=1),
  532. date(2021, 1, 30) + relativedelta(months=1),
  533. date(2021, 1, 29) + relativedelta(months=1),
  534. date(2021, 1, 28) + relativedelta(months=1),
  535. date(2021, 2, 28) + relativedelta(months=1),
  536. date(2021, 4, 30) + relativedelta(months=1),
  537. date(2021, 5, 31) + relativedelta(months=1),
  538. ] == [
  539. date(2021, 2, 28),
  540. date(2021, 2, 28),
  541. date(2021, 2, 28),
  542. date(2021, 2, 28),
  543. date(2021, 3, 28),
  544. date(2021, 5, 30),
  545. date(2021, 6, 30),
  546. ]
  547. def testDayOfMonthMinus(self):
  548. assert [
  549. date(2021, 2, 27) - relativedelta(months=1),
  550. date(2021, 3, 30) - relativedelta(months=1),
  551. date(2021, 3, 29) - relativedelta(months=1),
  552. date(2021, 3, 28) - relativedelta(months=1),
  553. date(2021, 5, 30) - relativedelta(months=1),
  554. date(2021, 6, 29) - relativedelta(months=1),
  555. ] == [
  556. date(2021, 1, 27),
  557. date(2021, 2, 28),
  558. date(2021, 2, 28),
  559. date(2021, 2, 28),
  560. date(2021, 4, 30),
  561. date(2021, 5, 29),
  562. ]
  563. def testLastDayOfMonthMinus(self):
  564. assert [
  565. date(2021, 2, 28) - relativedelta(months=1),
  566. date(2021, 3, 31) - relativedelta(months=1),
  567. date(2021, 5, 31) - relativedelta(months=1),
  568. date(2021, 6, 30) - relativedelta(months=1),
  569. ] == [
  570. date(2021, 1, 28),
  571. date(2021, 2, 28),
  572. date(2021, 4, 30),
  573. date(2021, 5, 30),
  574. ]
  575. class RelativeDeltaWeeksPropertyGetterTest(unittest.TestCase):
  576. """Test the weeks property getter"""
  577. def test_one_day(self):
  578. rd = relativedelta(days=1)
  579. self.assertEqual(rd.days, 1)
  580. self.assertEqual(rd.weeks, 0)
  581. def test_minus_one_day(self):
  582. rd = relativedelta(days=-1)
  583. self.assertEqual(rd.days, -1)
  584. self.assertEqual(rd.weeks, 0)
  585. def test_height_days(self):
  586. rd = relativedelta(days=8)
  587. self.assertEqual(rd.days, 8)
  588. self.assertEqual(rd.weeks, 1)
  589. def test_minus_height_days(self):
  590. rd = relativedelta(days=-8)
  591. self.assertEqual(rd.days, -8)
  592. self.assertEqual(rd.weeks, -1)
  593. class RelativeDeltaWeeksPropertySetterTest(unittest.TestCase):
  594. """Test the weeks setter which makes a "smart" update of the days attribute"""
  595. def test_one_day_set_one_week(self):
  596. rd = relativedelta(days=1)
  597. rd.weeks = 1 # add 7 days
  598. self.assertEqual(rd.days, 8)
  599. self.assertEqual(rd.weeks, 1)
  600. def test_minus_one_day_set_one_week(self):
  601. rd = relativedelta(days=-1)
  602. rd.weeks = 1 # add 7 days
  603. self.assertEqual(rd.days, 6)
  604. self.assertEqual(rd.weeks, 0)
  605. def test_height_days_set_minus_one_week(self):
  606. rd = relativedelta(days=8)
  607. rd.weeks = -1 # change from 1 week, 1 day to -1 week, 1 day
  608. self.assertEqual(rd.days, -6)
  609. self.assertEqual(rd.weeks, 0)
  610. def test_minus_height_days_set_minus_one_week(self):
  611. rd = relativedelta(days=-8)
  612. rd.weeks = -1 # does not change anything
  613. self.assertEqual(rd.days, -8)
  614. self.assertEqual(rd.weeks, -1)
  615. # vim:ts=4:sw=4:et