Python中的夏令时

jme*_*etz 11 python datetime pytz dst

我正在编写一个程序,它可以处理很多时区并将它们交叉.我最常处理的两件事是从"now"创建一个datetime对象,然后本地化一个天真的datetime对象.

要在太平洋时区创建一个日期时间对象,我目前正在这样做(python 2.7.2+)

from datetime import datetime
import pytz
la = pytz.timezone("America/Los_Angeles")
now = datetime.now(la)
Run Code Online (Sandbox Code Playgroud)

对于夏令时,这是正确的吗?如果没有,我想我应该这样做:

now2 = la.localize(datetime.now())
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么?任何人都可以告诉我第一个错误的情况,秒是对的?

至于我的秒问题,假设我在加利福尼亚州洛杉矶上午8:00的某个用户输入中有一个天真的日期和时间.是这样制作日期时间的正确方法:

la.localize(datetime(2012, 9, 1, 8, 0))
Run Code Online (Sandbox Code Playgroud)

如果没有,我应该如何构建这些日期时间?

Mar*_*som 20

pytz文档:

处理时间的首选方法是始终以UTC工作,仅在生成输出以供人类读取时转换为本地时间.

所以理想情况下你应该使用utcnow而不是now.

假设由于某种原因你的双手被捆绑并且你需要在当地时间工作,如果你在夏令时转换窗口期间这样做,你仍然会遇到尝试本地化当前时间的问题.同样datetime可能发生两次,一次是在白天时间,一次是在标准时间内,并且该localize方法不知道如何解决冲突,除非您明确告诉is_dst参数.

所以要获得当前的UTC时间:

utc = pytz.timezone('UTC')
now = utc.localize(datetime.datetime.utcnow())
Run Code Online (Sandbox Code Playgroud)

并将其转换为您当地的时间(但仅在必要时):

la = pytz.timezone('America/Los_Angeles')
local_time = now.astimezone(la)
Run Code Online (Sandbox Code Playgroud)

编辑:正如@JF Sebastian在评论中指出的那样,你的第一个使用例子datetime.now(tz)将适用于所有情况.如上所述,您的第二个示例在秋季过渡期间失败.我仍然主张使用UTC而不是本地时间用于除显示之外的所有内容.

  • 它确实有效:[什么时候`datetime.now(pytz_timezone)`失败?](http://stackoverflow.com/q/31886808/4279) (2认同)

use*_*413 6

关于DST,第一种解决方案是正确的,第二种解决方案是坏的.

我举个例子.在欧洲,运行此代码时:

from datetime import datetime
import pytz # $ pip install pytz

la = pytz.timezone("America/Los_Angeles")
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
now = datetime.now(la)
now2 = la.localize(datetime.now())
now3 = datetime.now()
print(now.strftime(fmt))
print(now2.strftime(fmt))
print(now3.strftime(fmt))
Run Code Online (Sandbox Code Playgroud)

我得到以下内容:

2012-08-30 12:34:06 PDT-0700
2012-08-30 21:34:06 PDT-0700
2012-08-30 21:34:06 
Run Code Online (Sandbox Code Playgroud)

datetime.now(la) 使用LA中的当前时间创建日期时间,以及LA的时区信息.

la.localize(datetime.now())将时区信息添加到天真的日期时间,但不进行时区转换; 它只是假设时间已经在这个时区.

datetime.now() 使用当地时间创建一个天真的日期时间(没有时区信息).

只要你在洛杉矶,你就不会看到差异,但是如果你的代码在其他地方运行,它可能不会做你想要的.

除此之外,如果您需要认真对待时区,最好将所有时间都用在UTC中,这样可以为DST省去很多麻烦.


MrE*_*MrE 5

这有效:

# naive datetime
d = datetime.datetime(2016, 11, 5, 16, 43, 45) 
utc = pytz.UTC # UTC timezone
pst = pytz.timezone('America/Los_Angeles') # LA timezone

# Convert to UTC timezone aware datetime
d = utc.localize(d) 
>>> datetime.datetime(2016, 11, 5, 16, 43, 45, tzinfo=<UTC>)

# show as in LA time zone (not converting here)
d.astimezone(pst) 
>>> datetime.datetime(2016, 11, 5, 9, 43, 45, 
tzinfo=<DstTzInfo 'America/Los_Angeles' PDT-1 day, 17:00:00 DST>)
# we get Pacific Daylight Time: PDT

# add 1 day to UTC date
d = d + datetime.timedelta(days=1) 
>>> datetime.datetime(2016, 11, 6, 16, 43, 45, tzinfo=<UTC>)

d.astimezone(pst) # now cast to LA time zone 
>>> datetime.datetime(2016, 11, 6, 8, 43, 45, 
tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>) 
# Daylight saving is applied -> we get Pacific Standard Time PST
Run Code Online (Sandbox Code Playgroud)

这不起作用:

# naive datetime
d = datetime.datetime(2016, 11, 5, 16, 43, 45) 
utc = pytz.UTC # UTC timezone
pst = pytz.timezone('America/Los_Angeles') # LA timezone

# convert to UTC timezone aware datetime
d = utc.localize(d) 
>>> datetime.datetime(2016, 11, 5, 16, 43, 45, tzinfo=<UTC>)

# convert to 'America/Los_Angeles' timezone: DON'T DO THIS
d = d.astimezone(pst) 
>>> datetime.datetime(2016, 11, 5, 9, 43, 45, 
tzinfo=<DstTzInfo 'America/Los_Angeles' PDT-1 day, 17:00:00 DST>) 
# we are in Pacific Daylight Time PDT

# add 1 day to LA local date: DON'T DO THAT
d = d + datetime.timedelta(days=1)
>>> datetime.datetime(2016, 11, 6, 9, 43, 45, 
tzinfo=<DstTzInfo 'America/Los_Angeles' PDT-1 day, 17:00:00 DST>) 
# Daylight Saving is NOT respected, we are still in PDT time, not PST
Run Code Online (Sandbox Code Playgroud)

结论:

datetime.timedelta() 考虑夏令时。

始终在 UTC 时区中添加/减去您的时间。转换为当地时间仅用于输出/显示。