我试图从datetime.datetime.today()的值中减去一个日期值,以计算多长时间以前的事情。但它抱怨道:
TypeError: can't subtract offset-naive and offset-aware datetimes
datetime.datetime.today()的返回值似乎不是“时区感知”,而我的其他日期值是。我如何从datetime.datetime.today()得到一个时区感知的返回值?
理想的解决方案是让它自动知道时区。
现在,它给我的时间是当地时间,恰好是PST,即UTC - 8小时。最坏的情况下,是否有一种方法我可以手动输入一个时区值到datetime.datetime.today()返回的datetime对象,并将其设置为UTC-8?
下面是一个适用于Python 2和Python 3的标准库解决方案:
from datetime import datetime
now = datetime.now(utc) # Timezone-aware datetime.utcnow()
today = datetime(now.year, now.month, now.day, tzinfo=utc) # Midnight
其中today是一个感知的datetime实例,表示UTC中的一天的开始(午夜),UTC是一个tzinfo对象(示例来自文档):
from datetime import tzinfo, timedelta
ZERO = timedelta(0)
class UTC(tzinfo):
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()
相关:几种获得给定UTC时间的午夜(一天的开始)的方法的性能比较。
注意:要获得具有非固定UTC偏移量的时区的午夜,这比较复杂。
在标准库中,如果不创建自己的时区类,就没有跨平台的方法来创建感知时区。(编辑:Python 3.9在提供此功能的标准库中引入了zoneinfo。)
在Windows上,有win32timezone.utcnow(),但这是pywin32的一部分。我宁愿建议使用pytz库,它有一个不断更新的大多数时区的数据库。
使用本地时区可能非常棘手(请参阅下面的“进一步阅读”链接),因此您可能更希望在整个应用程序中使用UTC,特别是用于计算两个时间点之间的差值这样的算术操作。
你可以像这样得到当前的日期/时间:
import pytz
from datetime import datetime
datetime.utcnow().replace(tzinfo=pytz.utc)
注意,datetime.today()和datetime.now()返回本地时间,而不是UTC时间,因此对它们应用.replace(tzinfo=pytz.utc)是不正确的。
另一种很好的方法是:
datetime.now(pytz.utc)
它更短一点,做同样的事情。
进一步阅读/观看为什么在许多情况下更喜欢UTC:
pytz文档
关于时间,每个开发人员都应该知道的——许多现实生活用例的开发提示
时间和时区的问题-电脑爱好者-关于使用时区的复杂性的有趣的,令人大开眼界的解释(视频)
需要强调的是,从Python 3.6开始,你只需要标准库来获得一个表示本地时间的时区感知datetime对象(操作系统的设置)。使用astimezone ()
import datetime
datetime.datetime(2010, 12, 25, 10, 59).astimezone()
# e.g.
# datetime.datetime(2010, 12, 25, 10, 59, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'Mitteleuropäische Zeit'))
datetime.datetime(2010, 12, 25, 12, 59).astimezone().isoformat()
# e.g.
# '2010-12-25T12:59:00+01:00'
# I'm on CET/CEST
(见@johnchen902的评论)。
注意,这里有一个小警告,不要期望timedelta时区有任何“dst感知”。
特别是对于非utc时区:
唯一具有自己方法的时区是timezone。但是如果你需要的话,你可以使用timedelta & timezone,并使用.replace强制使用一个带有任何utc偏移的时区。
In [1]: from datetime import datetime, timezone, timedelta
In [2]: def force_timezone(dt, utc_offset=0):
...: return dt.replace(tzinfo=timezone(timedelta(hours=utc_offset)))
...:
In [3]: dt = datetime(2011,8,15,8,15,12,0)
In [4]: str(dt)
Out[4]: '2011-08-15 08:15:12'
In [5]: str(force_timezone(dt, -8))
Out[5]: '2011-08-15 08:15:12-08:00'
使用timezone(timedelta(hours=n))作为时区是这里真正的银弹,它还有许多其他有用的应用程序。