Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
521 views
in Technique[技术] by (71.8m points)

python - Timezone offset sign reversed by dateutil?

Does anyone know why python's dateutil reverses the sign of the GMT offset when it parses the datetime field?

Apparently this feature is a known outcome of not only dateutil but also other parsing functions. But this results in an incorrect datetime result unless a pre-processing hack is applied:

from dateutil import parser

jsDT = 'Fri Jan 02 2015 03:04:05.678910 GMT-0800'
python_datetime = parser.parse(jsDT)
print(python_datetime)
>>> 2015-01-02 03:04:05.678910+08:00

jsDT = 'Fri Jan 02 2015 03:04:05.678910 GMT-0800'
if '-' in jsDT:
    jsDT = jsDT.replace('-','+')
elif '+' in jsDT:
    jsDT = jsDT.replace('+','-')
python_datetime = parser.parse(jsDT)
print(python_datetime)
>>> 2015-01-02 03:04:05.678910-08:00
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It seems dateutil uses POSIX-style signs here. It is not related to Python. Other software does it too. From the tz database:

# We use POSIX-style signs in the Zone names and the output abbreviations,
# even though this is the opposite of what many people expect.
# POSIX has positive signs west of Greenwich, but many people expect
# positive signs east of Greenwich.  For example, TZ='Etc/GMT+4' uses
# the abbreviation "GMT+4" and corresponds to 4 hours behind UT
# (i.e. west of Greenwich) even though many people would expect it to
# mean 4 hours ahead of UT (i.e. east of Greenwich).

The tz database is used almost everywhere.

Example:

$ TZ=Etc/GMT-8 date +%z
+0800

You probably expect a different timezone:

>>> from datetime import datetime
>>> import pytz
>>> pytz.timezone('America/Los_Angeles').localize(datetime(2015, 1, 2, 3, 4, 5, 678910), is_dst=None).strftime('%Y-%m-%d %H:%M:%S.%f %Z%z')
'2015-01-02 03:04:05.678910 PST-0800'

Note: PST, not GMT.

Though dateutil uses POSIX-style signs even for the PST timezone abbreviation:

>>> from dateutil.parser import parse
>>> str(parse('2015-01-02 03:04:05.678910 PST-0800'))
'2015-01-02 03:04:05.678910+08:00'

datetime.strptime() in Python 3 interprets it "correctly":

$ TZ=America/Los_Angeles python3                                               
...
>>> from datetime import datetime
>>> str(datetime.strptime('2015-01-02 03:04:05.678910 PST-0800', '%Y-%m-%d %H:%M:%S.%f %Z%z'))
'2015-01-02 03:04:05.678910-08:00'

Notice the sign.

Despite the confusion due to POSIX-style signs; dateutil behavior is unlikely to change. See dateutil bug: "GMT+1" is parsed as "GMT-1" and @Lennart Regebro's reply:

Parsing GTM+1 this way is actually a part of the Posix specification. This is therefore a feature, and not a bug.

See how TZ environment variable is defined in the POSIX specification, glibc uses similar definition.

It is not clear why dateutil uses POSIX TZ-like syntax to interpret the timezone info in a time string. The syntax is not exactly the same e.g., POSIX syntax requires a semicolon: hh[:mm[:ss]] in the utc offset that is not present in your input.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...