Python dateutil.parser throws "ValueError: day is out of range for month"
Asked Answered
L

2

10

I have a the following code that runs fine with input format like {Year}/{Month} except when it comes to 1994/02

Here is the sample code

>>> import dateutil.parser as dtp
>>> dtp.parse('1994/01')
datetime.datetime(1994, 1, 29, 0, 0)
>>> dtp.parse('1994/03')
datetime.datetime(1994, 3, 29, 0, 0)
>>> dtp.parse('1994/02')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/antony/.virtualenvs/comp-invest/lib/python2.7/site-packages/dateutil/parser.py", line 720, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
  File "/Users/antony/.virtualenvs/comp-invest/lib/python2.7/site-packages/dateutil/parser.py", line 317, in parse
    ret = default.replace(**repl)
ValueError: day is out of range for month

As you can see, the code works fine with 1994/01 and 1994/03, but fails with 1994/02 Does this have anything to do with leap year? But more important, how do I get around this problem and make my code work again?

Thanks

Lendlease answered 30/1, 2013 at 1:52 Comment(3)
It looks like it is defaulting to 29 (today's day) for the day and there isn't normally 29 days in February. Not sure if February 1994 was a leap year.Delia
For the record, 1994 was not (1992 and 1996 were).Winder
Ran into the same thing. One of my favorite "features" in a long time. Code that only breaks at the end of a month...Floc
F
13

dtp.parse is filling in the missing day with the current date's day. You ran the code on 2013/01/29 and day 29 does not exist in February (i.e. 1994/02/29).

Use this instead:

dtp.parse('1994/01'+'/01')

It will give consistent results (first day of month) regardless of when the code is executed.

Facilitate answered 30/1, 2013 at 1:56 Comment(2)
you can derive that from the returned value by the way datetime.datetime(1994, 1, 29, 0, 0).Facilitate
Thanks! I must be tired..so I didn't connect the dots. In fact, the code did not run into issues until today...so I was rather puzzled about that, but you are a genius at pointing out the real cause. Thanks! SO doesn't let me mark you as answer until 7 min later..so give it another 7 or so, and I will mark this as answered. Thanks!Lendlease
S
3

This was a bug in dateutil that has since been fixed. Version 2.5.0 and higher will no longer have this issue.

If you must use an earlier version, I think that the "correct" way to handle things is to specify the default parameter:

from dateutil.parser import parse
from datetime import datetime, date

# First of the current month, at midnight.
default_date = datetime.combine(date.today(), datetime.min.time()).replace(day=1)
dt = parse('1994/01', default=default_date)

This will default to the 1st of the month rather than the current day.

Sake answered 25/3, 2016 at 19:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.