1

Is it safe to multiply relativedelta objects? I'm seeing some weird and inconsistent behaviour, and can't find it documented what sorts of arithmetic are supported by this class (if any)

>>> from datetime import datetime
>>> from dateutil.relativedelta import relativedelta
>>> datetime.now() + relativedelta(days=2)
datetime.datetime(2014, 5, 30, 12, 24, 59, 173941)
>>> datetime.now() + relativedelta(days=1) * 2
# TypeError: integer argument expected, got float

On the other hand:

>>> relativedelta(days=2) == relativedelta(days=1) * 2
True

Full traceback (with python 2.7.5 and dateutil 1.5):

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/dateutil/relativedelta.py", line 261, in __radd__
    day = min(calendar.monthrange(year, month)[1],
  File "/usr/lib/python2.7/calendar.py", line 121, in monthrange
    day1 = weekday(year, month, 1)
  File "/usr/lib/python2.7/calendar.py", line 113, in weekday
    return datetime.date(year, month, day).weekday()
TypeError: integer argument expected, got float
legoscia
  • 39,593
  • 22
  • 116
  • 167
wim
  • 338,267
  • 99
  • 616
  • 750
  • 1
    I don't get such a `TypeError`. I get `datetime.datetime(2014, 5, 30, 12, 45, 2, 181770)` instead. What version of `python-dateutil` have you got installed? I used Python 2.7 and `python-dateutil` 2.2. – Martijn Pieters May 28 '14 at 11:45
  • As for *is it safe to multiply*: yes, the type specifically implements both `__mul__` and `__rmul__` methods for this use-case. But I cannot reproduce your problem at all. – Martijn Pieters May 28 '14 at 12:18
  • I can reproduce, using Python 2.7.5+. The exceptions seems to occur when you try to add a `relativedelta` that is the result of a multiplication, even when you do `* 1` – tobias_k May 28 '14 at 12:25
  • @tobias_k: I still can't. Care to share an example session? The full traceback even would be of some use. – Martijn Pieters May 28 '14 at 12:26
  • @tobias_k: the source code of `__mul__` turns the other argument into a float, multiplies the relative components and turns the results back into integers. I don't see how that could lead to a `relativedelta()` instance that bombs out this way. A full traceback would at least help me trace back to a scenario where the error might occur, but that's sadly missing from this post. Hence my VtC as lacking info. – Martijn Pieters May 28 '14 at 12:29
  • @MartijnPieters I just checked the types of the various fields of the `relativedelta` object. Before, they are all `int`, but after the multiplication, they are all `float`. Seems this is a problem with Python 2.7.x that was fixed in later versions. – tobias_k May 28 '14 at 12:31
  • @tobias_k: I'd say it's a problem with the version of `dateutil` then, because the version I have installed (2.2, latest), clearly uses `int()` for all values. – Martijn Pieters May 28 '14 at 12:31
  • @tobias_k: see http://bazaar.launchpad.net/~dateutil/dateutil/trunk/view/head:/dateutil/relativedelta.py#L367, and more importantly [this revision](http://bazaar.launchpad.net/~dateutil/dateutil/trunk/revision/116); looks like you (and wim perhaps) have an outdated version? – Martijn Pieters May 28 '14 at 12:33
  • `dateutil` 1.5 in my case. See edit to the question. – tobias_k May 28 '14 at 12:36
  • It was indeed `dateutil` v1.5, I should have included that in my original post - thanks for the edit @tobias_k ! – wim May 28 '14 at 13:44

1 Answers1

4

You've run into a known bug in relativedelta's handling of multiplication, since fixed. It only affects Python 2.7 or newer (call signatures of certain functions were tightened).

Upgrade your python-dateutils package to version 2.1 or newer.

Don't be put off by the 2.0-is-Python-3-only misinformation on the project documentation; 2.1 and 2.2 are Python 2 and 3 cross-compatible.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343