我试图从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?


当前回答

在utc时区中获取一个支持时区的日期就足以让日期减法工作了。

但是如果你想要一个当前时区的时区感知日期,tzlocal是最好的方法:

from tzlocal import get_localzone  # pip install tzlocal
from datetime import datetime
datetime.now(get_localzone())

PS dateutil具有类似的函数(dateutil.tz.tzlocal)。但是尽管共享名称,但它有一个完全不同的代码库,正如J.F.塞巴斯蒂安所指出的那样,这可能会给出错误的结果。

其他回答

下面是一个适用于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偏移量的时区的午夜,这比较复杂。

下面是一个使用可读时区的解决方案,它与today()一起工作:

from pytz import timezone

datetime.now(timezone('Europe/Berlin'))
datetime.now(timezone('Europe/Berlin')).today()

所有时区列表如下:

import pytz

pytz.all_timezones
pytz.common_timezones # or

另一种构造表示当前时间的时区感知datetime对象的方法:

import datetime
import pytz

pytz.utc.localize( datetime.datetime.utcnow() )  

你可以通过以下命令从PyPI安装pytz:

$ pipenv install pytz

特别是对于非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))作为时区是这里真正的银弹,它还有许多其他有用的应用程序。

获取特定时区的当前时间:

import datetime
import pytz
my_date = datetime.datetime.now(pytz.timezone('US/Pacific'))

记得先安装pytz。