49

I'm using dateutil.parser.parse to format a date from a string. But now it mixes up the month and the day.

I have a string that contains 05.01.2015. After

dateutil.parser.parse("05.01.2015")

it returns:

datetime.datetime(2015, 5, 1, 0, 0)

I hoped the it would return (2015, 1, 5, 0, 0)

How can I tell the code that the format is dd.mm.yyyy?

For the record, 25.01.2015 will be parsed as (2015, 1, 25, 0, 0), as expected.

Alex Riley
  • 169,130
  • 45
  • 262
  • 238
Timo002
  • 3,138
  • 4
  • 40
  • 65

2 Answers2

84

Specify dayfirst=True:

>>> dateutil.parser.parse("05.01.2015", dayfirst=True)
datetime.datetime(2015, 1, 5, 0, 0)

This gives precedence to the DD-MM-YYYY format instead of MM-DD-YYYY in cases where the date format is ambiguous (e.g. when the day is 12 or lower). The function is documented here.

Alex Riley
  • 169,130
  • 45
  • 262
  • 238
  • Tnx, this did the job! I have been looking in the documentation you where referring to, but couldn't find anything. But now it's working fine! (I created this code after 12-12-2014, so automatically everything went well.) – Timo002 Jan 06 '15 at 14:35
  • 4
    As a warning, note that even with `dayfirst=True` if you pass a "malformed" date such as `01.13.2015`, `parse` will ignore `dayfirst` and interpret `month=1` and `day=13`, which could lead to unexpected behaviour. – Diego Milán Jun 13 '19 at 19:29
  • the way I deal with this is I run all 4 combos of dayfirst and yearfirst and stick the results in a set, if the set has more than one thing in it at the end I raise an "Ambiguous value" error – Gordon Wrigley Nov 02 '20 at 09:46
  • Be careful because it also gives precedence to YDM instead of YMD, making it so it fails to correctly parse an ISO 8601 formatted date (`2022-01-06` will be parsed as 1st of June, not 6th of January). There doesn't seem to be a way of making it give preference to DMY over MDY without making it prefer YDM over YMD. – Zezombye Aug 29 '22 at 15:05
5

You asked, 'How can I tell the code that the format is dd.mm.yyyy?'

Since you have already imported dateutil then most direct answer might be to specify the format of the date string but this is quite ugly code:

>>> dateutil.parser.datetime.datetime.strptime(date_string, '%d.%m.%Y')
datetime.datetime(2015, 1, 5, 0, 0)

We can see an obvious alternative embedded in the code. You could use that directly.

>>> from datetime import datetime
>>> datetime.strptime(date_string, '%d.%m.%Y')
datetime.datetime(2015, 1, 5, 0, 0)

There are also some newer alternative libraries that offer methods and properties aplenty.

Simplest to use in this case would be arrow:

>>> import arrow
>>> arrow.get(date_string, 'DD.MM.YYYY')
<Arrow [2015-01-05T00:00:00+00:00]>

Although I find the formatting for arrow easier to remember, pendulum uses Python's old formatting system which might save you having to learn arrow's.

>>> import pendulum
>>> pendulum.datetime.strptime(date_string, '%d.%m.%Y')
<Pendulum [2015-01-05T00:00:00+00:00]>
Bill Bell
  • 21,021
  • 5
  • 43
  • 58