Python's datetime strptime() inconsistent between machines
Asked Answered
M

2

5

I'm stumped. The date-cleaning functions I wrote work in Python 2.7.5 on my Mac but not in 2.7.6 on my Ubuntu server.

Python 2.7.5 (default, Mar  9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from datetime import datetime
>>> date = datetime.strptime('2013-08-15 10:23:05 PDT', '%Y-%m-%d %H:%M:%S %Z')
>>> print(date)
2013-08-15 10:23:05

Why does this not work in 2.7.6 on Ubuntu?

Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from datetime import datetime
>>> date = datetime.strptime('2013-08-15 10:23:05 PDT', '%Y-%m-%d %H:%M:%S %Z')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/_strptime.py", line 325, in _strptime
    (data_string, format))
ValueError: time data '2013-08-15 10:23:05 PDT' does not match format '%Y-%m-%d %H:%M:%S %Z'

Edit: I tried using the timezone offset with the lowercase %z, but still get an error (although a different one):

>>> date = datetime.strptime('2013-08-15 10:23:05 -0700', '%Y-%m-%d %H:%M:%S %z')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_strptime.py", line 317, in _strptime
    (bad_directive, format))
ValueError: 'z' is a bad directive in format '%Y-%m-%d %H:%M:%S %z'
Matherne answered 10/9, 2014 at 20:0 Comment(14)
Just to narrow it down, same machine or different machines?Forswear
Oh, just noticed the different OSes, so clearly different machines.Forswear
Different machines. I have 2.7.5 on my Mac but the server (Ubuntu) I'm trying to run the script on has 2.7.6.Matherne
I am thinking that it's more likely to do with the underlying operating systems or with how the two machines are configured than with any differences between 2.7.5 and 2.7.6.Forswear
Are both machines in a locale where the time zone is PDT? %Z will only match PDT if the machine's local time zone name is PDT.Six
docs.python.org/2/library/time.html#time.strptime says "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)." This might shed some light.Forswear
@Six I didn't realize that's how it worked. How do I read in dates that have different time zones on a single machine? There will be dates in PDT, GMT, etc. that I'll need to convert to date objects.Matherne
@NicoleWhite: You're welcome (not that it helps much in solving the actual problem).Forswear
I think @Six might be on to something. I get the same ValueError when I run the code on my Mac (which has exactly the same version of Python as your Mac, but is configured for a timezone other than PDT).Forswear
@NicoleWhite: Parsing the timezone abbreviation is problematic because they do not uniquely specify a timezone. For example, EST can mean Eastern Standard Time in the US, or it could mean Eastern Summer Time in Australia. (More on this, with links, here)Six
@Six Ok. I can convert all of them to their offsets, but in my edits you can see that the %z doesn't work either. bugs.python.org/issue6641Matherne
can you check what you get from import time and then time.tzname on your machine? Any other value apart from these may failTorbernite
@PacificStickler Right. I get ('UTC', 'UTC'), so I'll have to figure something out.Matherne
@Six Can you go ahead and add your comments as an answer?Matherne
S
5

Timezone abbreviations are ambiguous. For example, EST can mean Eastern Standard Time in the US, or it could mean Eastern Summer Time in Australia.

Therefore, datetime strings which contain timezone abbreviations can not be reliably parsed into timezone-aware datetime objects.

strptime's '%Z' format will only match UTC, GMT or the timezone abbreviation listed in time.tzname, which is machine-locale dependent.

If you can change the datetime strings to ones containing UTC offsets, then you could use dateutil to parse the strings into timezone-aware datetime objects:

import dateutil
import dateutil.parser as DP
date = DP.parse('2013-08-15 10:23:05 -0700')
print(repr(date))
# datetime.datetime(2013, 8, 15, 10, 23, 5, tzinfo=tzoffset(None, -25200))
Six answered 10/9, 2014 at 20:46 Comment(1)
Thanks. With your method and str.replace('PDT', '-0700') I'm good to go.Matherne
T
3

%Z will only accept GMT, UTC, and whatever is listed in time.tzname, since the time zone functionality is platform specific, as is given here:

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).

So try to figure out what time zones are supported by your platform by running the following:

import time
time.tzname

I get the following:

('PST', 'PDT')

Thus, your best bet might be to convert your time beforehand to one of the default allowed time zones.

Torbernite answered 10/9, 2014 at 20:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.