也许这是一个凌晨4点的bug,但我认为我做的一切都是正确的,但它似乎不像DST是从UTC时间戳转换到本地化的日期时间。
>>> from datetime import datetime
>>> import pytz
>>> eastern = pytz.timezone("US/Eastern")
>>> utc = pytz.utc
>>> local_now = eastern.localize(datetime.now())
>>> utc_now = local_now.astimezone(utc)
>>> seconds = int(utc_now.strftime("%s"))
>>> utc_then = utc.localize(datetime.fromtimestamp(seconds))
>>> local_then = utc_then.astimezone(eastern)
>>> print utc_now, utc_then
2013-06-16 10:05:27.893005+00:00 2013-06-16 11:05:27+00:00
>>> print local_now, local_then
2013-06-16 06:05:27.893005-04:00 2013-06-16 07:05:27-04:00
o------------o
| | DT.datetime.utcfromtimestamp (*)
| |<-----------------------------------o
| | |
| datetime | |
| | DT.datetime.fromtimestamp |
| |<----------------------------o |
| | | |
o------------o | |
| ^ | |
.timetuple | | | |
.utctimetuple | | DT.datetime(*tup[:6]) | |
v | | |
o------------o o------------o
| |-- calendar.timegm (*) -->| |
| | | |
| |---------- time.mktime -->| |
| timetuple | | timestamp |
| |<-- time.localtime -------| |
| | | |
| |<-- time.gmtime (*)-------| |
o------------o o------------o
(*) Interprets its input as being in UTC and returns output in UTC
如图所示,当您有一个UTC的日期时间,例如utc_now
,要获取它的时间戳,请使用
seconds = calendar.timegm(utc_date.utctimetuple())
当您有时间戳时,要获得UTC的日期时间,请使用
DT.datetime.utcfromtimestamp(seconds)
import datetime as DT
import pytz
import calendar
eastern = pytz.timezone("US/Eastern")
utc = pytz.utc
now = DT.datetime(2013, 6, 16, 10, 0, 0)
local_now = eastern.localize(now)
utc_now = local_now.astimezone(utc)
seconds = calendar.timegm(utc_now.utctimetuple())
print(seconds)
# 1371391200
utc_then = utc.localize(DT.datetime.utcfromtimestamp(seconds))
local_then = utc_then.astimezone(eastern)
print utc_now, utc_then
# 2013-06-16 14:00:00+00:00 2013-06-16 14:00:00+00:00
print local_now, local_then
# 2013-06-16 10:00:00-04:00 2013-06-16 10:00:00-04:00
p。注意,timetuple()
和utctimetuple()
方法减少了日期时间的微秒数。要以保留微秒的方式将日期时间转换为时间戳,请使用mata的解决方案。
如果您想编写可移植代码,您应该避免使用datetime.now
,因为它总是使用本地时区,因此local_now = eastern.localize(datetime.now())
仅在本地机器上的时区为东部时才会工作。总是尝试使用utcnow
,出于同样的原因,utcfromtimestamp
。
同样,使用strftime("%s")
将日期时间转换为时间戳也不起作用。
from datetime import datetime
import pytz
utc_now = pytz.utc.localize(datetime.utcnow())
eastern = pytz.timezone("US/Eastern")
local_now = utc_now.astimezone(eastern)
# seconds = utc_now.timestamp() python3
seconds = (utc_now - pytz.utc.localize(datetime.utcfromtimestamp(0))).total_seconds()
utc_then = pytz.utc.localize(datetime.utcfromtimestamp(seconds))
local_then = utc_then.astimezone(eastern)
print("%s - %s" % (utc_now, utc_then))
print("%s - %s" % (local_now, local_then))
要获得您的本地时区作为pytz.timezone
对象,您可以使用tzlocal
模块:
#!/usr/bin/env python
from datetime import datetime
import pytz # pip install pytz
from tzlocal import get_localzone # pip install tzlocal
local_tz = get_localzone()
local_now = datetime.now(local_tz)
utc_now = local_now.astimezone(pytz.utc)
seconds = (utc_now - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
utc_then = datetime.fromtimestamp(seconds, pytz.utc)
local_then = utc_then.astimezone(local_tz)
print("%s %s" % (utc_now, utc_then))
print("%s %s" % (local_now, local_then))
- 不要使用
datetime.now()
——它可能是模棱两可的,例如,在DST更改期间。要么像我的例子中那样显式传递tzinfo,要么使用datetime.utcnow()
- 不要使用
utc_now.strftime('%s')
——它忽略时区信息(它使用当前的本地时区),并且它是不可移植的。使用datetime.timestamp()
方法或类似方法代替 - 不要使用
utc.localize(datetime.fromtimestamp(seconds))
—.fromtimestamp()
返回一个朴素的datetime对象在本地时区,可能与UTC不同。要么像我的例子中那样显式传递tzinfo,要么使用datetime.utcfromtimestamp()
来获得一个表示UTC时间 的朴素datetime对象。 - 不要将
datetime.utctimetuple()
用于幼稚的datetime对象——它不会将它们转换为UTC。如果对象已经是UTC:utc_now.timetuple()
返回相同的时间。
使用localize(is_dst=None)
:
aware_dt = tz.localize(naive_dt, is_dst=None)
如果没有is_dst=None
,则在夏令时更改时tz.localize()
返回错误结果的概率为50%。如果在你的特定情况下得到一个可能错误的结果而不是一个异常,那么你可以通过显式的is_dst=False
来提醒你自己。
一般来说,如果源时区和目标时区都不是UTC, pytz
文档建议在.astimezone()
调用之后调用tz.normalize()
。