3

Possible Duplicate:
Python strptime() and timezones?

'Saturday, December 22, 2012 1:22:24 PM EST' does not match format '%A, %B %d, %Y %I:%M:%S %p %Z'

Maybe I'm missing something but can anyone spot why this doesn't validate properly?

Community
  • 1
  • 1
Dharun
  • 613
  • 8
  • 26

4 Answers4

2

The strptime() function cannot handle %Z timezone parsing very well. Only UTC and GMT are really supported, and the current value of time.tzname. See the strptime documenation:

Support for the %Z directive is based on the values contained in tzname and whether daylight is true. Because of this, it is platform-specific except for recognizing UTC and GMT which are always known (and are considered to be non-daylight savings timezones).

Removing the EST part of your input and the %Z part of your format string makes things work:

>>> import time
>>> time.strptime('Saturday, December 22, 2012 1:22:24 PM EST', '%A, %B %d, %Y %I:%M:%S %p %Z')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/_strptime.py", line 454, in _strptime_time
    return _strptime(data_string, format)[0]
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/_strptime.py", line 325, in _strptime
    (data_string, format))
ValueError: time data 'Saturday, December 22, 2012 1:22:24 PM EST' does not match format '%A, %B %d, %Y %I:%M:%S %p %Z'
>>> time.strptime('Saturday, December 22, 2012 1:22:24 PM', '%A, %B %d, %Y %I:%M:%S %p')
time.struct_time(tm_year=2012, tm_mon=12, tm_mday=22, tm_hour=13, tm_min=22, tm_sec=24, tm_wday=5, tm_yday=357, tm_isdst=-1)

or replacing the timezone EST with GMT:

>>> time.strptime('Saturday, December 22, 2012 1:22:24 PM GMT', '%A, %B %d, %Y %I:%M:%S %p %Z')
time.struct_time(tm_year=2012, tm_mon=12, tm_mday=22, tm_hour=13, tm_min=22, tm_sec=24, tm_wday=5, tm_yday=357, tm_isdst=0)

To parse strings with a timezone other than time.tzname, GMT or UTC, use a different date parsing library. The dateutil library has an excellent parse function that handles timezones properly:

>>> from dateutil.parser import parse
>>> parse('Saturday, December 22, 2012 1:22:24 PM EST', tzinfos={'EST': -18000})
datetime.datetime(2012, 12, 22, 13, 22, 24, tzinfo=tzoffset(u'EST', -18000))

When using dateutil.parser.parse() you do have to provide your own timezone offsets for your format though.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • The date parser will give the correct datetime object only for the above case. But consider the below case,`>>> parse('Saturday, 13-12-11 1:22:24 PM EST', tzinfos={'EST': -18000}) datetime.datetime(2011, 12, 13, 13, 22, 24, tzinfo=tzoffset('EST', -18000)) >>> >>> >>> parse('Saturday, 09-12-11 1:22:24 PM EST', tzinfos={'EST': -18000}) datetime.datetime(2011, 9, 12, 13, 22, 24, tzinfo=tzoffset('EST', -18000))`. The datetimeobject.date() differs for both the case.. – Darknight Dec 28 '12 at 13:56
  • 1
    @PSivachandran: That's because the date is *ambiguous*. There are no 13 months, so the first example it's clear that the format is in day-month-year order, but the second one can be interpreted both as day-month-year and month-day-year. The default is to parse dates as the latter, you can change that with the `dayfirst=True` keyword. – Martijn Pieters Dec 28 '12 at 14:03
  • @Marijn: Great. Thanks. I didn't know this `dayfirst` keyword. Without this I was totally confused. +1 for your explanation. – Darknight Dec 28 '12 at 14:14
1

You can save yourself a lot of trouble and use dateutil.

In [1]: from dateutil import parser

In [2]: parser.parse('Saturday, December 22, 2012 1:22:24 PM EST')
Out[2]: datetime.datetime(2012, 12, 22, 13, 22, 24)

As for the ambiguity pointed out by eumiro, you could add a tzinfo argument:

In [3]: parser.parse('Saturday, December 22, 2012 1:22:24 PM EST',tzinfos={'EST':-5*3600})
Out[3]: datetime.datetime(2012, 12, 22, 13, 22, 24, tzinfo=tzoffset('EST', -18000))
root
  • 76,608
  • 25
  • 108
  • 120
  • The trouble is still there. It ignores the `EST` timezone, (correctly, since it can be both American and Australian: http://www.timeanddate.com/library/abbreviations/timezones/) – eumiro Dec 28 '12 at 09:46
  • 1
    @ eumiro - you are right. I think you could possibly add `tzinfos` arg when parsing to handle it. – root Dec 28 '12 at 09:58
  • great, didn't know about `tzinfos`. – eumiro Dec 28 '12 at 10:06
1

As @root suggested dateutil.parser is the robust way to parse date, but just to clarify about the issue here

I just saw the code in _strptime.py and it seems the supported time zones are

["utc", "gmt", time.tzname[0].lower()]

and in case, the current locale timezone supports daylight saving, it would append

time.tzname[0].lower() to the above list.

So when using strptime, ensure that the timezone on which you are parsing the date supports the source timezone

Here is the code for reference

def __calc_timezone(self):
    # Set self.timezone by using time.tzname.
    # Do not worry about possibility of time.tzname[0] == timetzname[1]
    # and time.daylight; handle that in strptime .
    try:
        time.tzset()
    except AttributeError:
        pass
    no_saving = frozenset(["utc", "gmt", time.tzname[0].lower()])
    if time.daylight:
        has_saving = frozenset([time.tzname[1].lower()])
    else:
        has_saving = frozenset()
    self.timezone = (no_saving, has_saving)
Abhijit
  • 62,056
  • 18
  • 131
  • 204
0

Most likely your locale timezone is empty, e.g. %Z evaluates to '' You can test this by:

>>> fmt = '%A, %B %d, %Y %I:%M:%S %p %Z'
>>> datetime.strptime(datetime.strftime(datetime.now(), fmt), fmt)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/_strptime.py", line 325, in _strptime
    (data_string, format))
ValueError: time data 'Friday, December 28, 2012 11:34:35 AM ' does not match format '%A, %B %d, %Y %I:%M:%S %p %Z'
Kimvais
  • 38,306
  • 16
  • 108
  • 142