Python:如何获得“timezone aware”的datetime.today()值?

时间:2010-12-25 10:59:50

标签: python datetime date timezone

我试图从datetime.today()的值中减去一个日期值来计算多久以前的事情。但它抱怨道:

TypeError: can't subtract offset-naive and offset-aware datetimes

datetime.today()似乎不是“时区感知”,而我的其他日期值是。如何获得时区感知的datetime.today()值?现在它给了我当地时间的时间,恰好是PST,即UTC-8hrs。最坏的情况是,有没有办法我可以手动将时区值输入datetime返回的datetime.today()对象并将其设置为UTC-8?当然,理想的解决方案是让它自动知道时区。

19 个答案:

答案 0 :(得分:305)

在标准库中,没有创建自己的时区类的创建感知时区的跨平台方式。

在Windows上,有win32timezone.utcnow(),但这是pywin32的一部分。我宁愿建议使用pytz library,它有一个不断更新的大多数时区数据库。

使用本地时区可能非常棘手(请参阅下面的“进一步阅读”链接),因此您可能更愿意在整个应用程序中使用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:

答案 1 :(得分:90)

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

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

答案 2 :(得分:42)

在Python 3中,标准库使得将UTC指定为时区变得更加容易:

>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2016, 8, 26, 14, 34, 34, 74823, tzinfo=datetime.timezone.utc)

如果您想要一个仅使用标准库并且同时适用于Python 2和Python 3的解决方案,请参阅J. F. Sebastien's answer

答案 3 :(得分:17)

这是一个适用于Python 2和3的stdlib解决方案:

from datetime import datetime

now = datetime.now(utc) # timezone-aware datetime.utcnow()
today = datetime(now.year, now.month, now.day, tzinfo=utc) # midnight

其中today是一个知晓的日期时间实例,表示以UTC开头的一天(午夜),而utc是一个tzinfo对象(example from the docs):

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()

相关:several ways to get midnight (start of a day) for a given UTC time的效果比较 注意:它更复杂,get midnight for a time zone with a non-fixed utc offset

答案 4 :(得分:13)

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

import datetime
import pytz

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

答案 5 :(得分:9)

如果您使用的是Django,则可以将日期设置为非tz(仅限utc)。

评论 settings.py中的以下行:

USE_TZ = True

答案 6 :(得分:6)

以下是使用stdlib生成它的一种方法:

import time
from datetime import datetime

FORMAT='%Y-%m-%dT%H:%M:%S%z'
date=datetime.strptime(time.strftime(FORMAT, time.localtime()),FORMAT)

日期将存储本地日期和偏离UTC ,而不是UTC时区的日期,因此如果您需要识别,可以使用此解决方案在生成日期的时区。在这个例子和我当地的时区:

date
datetime.datetime(2017, 8, 1, 12, 15, 44, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)))

date.tzname()
'UTC+02:00'

关键是将%z指令添加到表示FORMAT,以指示生成的时间结构的UTC偏移量。其他表示格式可以在日期时间模块docs

中查阅

如果您需要UTC时区的日期,可以将 time.localtime()替换为 time.gmtime()

date=datetime.strptime(time.strftime(FORMAT, time.gmtime()),FORMAT)

date    
datetime.datetime(2017, 8, 1, 10, 23, 51, tzinfo=datetime.timezone.utc)

date.tzname()
'UTC'

修改

这仅适用于python3 。 z指令在python 2 _strptime.py code

上不可用

答案 7 :(得分:6)

pytz是一个Python库,允许使用Python 2.3或更高版本进行准确的跨平台时区计算。

使用stdlib,这是不可能的。

SO上查看类似的问题。

答案 8 :(得分:4)

为什么不使用dateutil,如下所述: http://joelinoff.com/blog/?p=802

from dateutil.tz import tzlocal
# Get the current date/time with the timezone.
now = datetime.datetime.now(tzlocal())

答案 9 :(得分:4)

应该强调的是,从Python 3.6开始,您只需要标准的lib即可获取时区感知的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的评论)。请注意,astimezone(None) gives aware datetime, unaware of DST是一个小警告。

答案 10 :(得分:2)

您可以使用timezone创建本地datetime,方法是解析使用time.strftime指令(在Python 3.3中引入)的%z调用的输出,为{{ 3}}。您可以使用timezone创建一个带有一行的知名datetime实例:

import time
from datetime import datetime

aware_local_now = datetime.now(
    tz=datetime.strptime(time.strftime("%z", time.localtime()), "%z").tzinfo)

print(aware_local_now)
2018-03-01 13:41:26.753644-08:00

答案 11 :(得分:2)

这是使用可读时区的解决方案,并且可以与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

答案 12 :(得分:1)

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.Sebastian的noted可能会给出错误的结果。

答案 13 :(得分:1)

“ howchoo”中的泰勒写了一篇非常出色的文章,帮助我更好地了解了Datetime对象,请点击以下链接

Working with Datetime

基本上,我只是将以下内容添加到两个datetime对象的末尾

.replace(tzinfo=pytz.utc)

示例:

import pytz
import datetime from datetime

date = datetime.now().replace(tzinfo=pytz.utc)

答案 14 :(得分:0)

如果你在python中获得当前的时间和日期然后导入日期和时间,python包在python之后你会得到当前的日期和时间,如...

from datetime import datetime
import pytz
import time
str(datetime.strftime(datetime.now(pytz.utc),"%Y-%m-%d %H:%M:%S%t"))

答案 15 :(得分:0)

使用如下所示的时区作为时区感知日期时间,默认为UTC:

    from django.utils import timezone
    today = timezone.now() 

答案 16 :(得分:0)

尝试pnp_datetime,所有使用和返回的时间都是时区,并且不会引起任何天真偏移和可感知偏移的问题。

>>> from pnp_datetime.pnp_datetime import Pnp_Datetime
>>>
>>> Pnp_Datetime.utcnow()
datetime.datetime(2020, 6, 5, 12, 26, 18, 958779, tzinfo=<UTC>)

答案 17 :(得分:0)

这对我有用,我首先尝试获取val counter = object: CountUpTimer(30, 1){ override fun onCount(count: Int) { Log.i("Counter", "Counting: $count") } override fun onFinish() { Log.i("Counter", "Counting done") } } counter.start() 时间,然后根据您要设置的时区来增加或减少小时数。

UTC

答案 18 :(得分:-1)

在我看来,另一个替代方案是使用Pendulum代替pytz。请考虑以下简单代码:

>>> import pendulum

>>> dt = pendulum.now().to_iso8601_string()
>>> print (dt)
2018-03-27T13:59:49+03:00
>>>

要安装Pendulum并查看其文档,请转到here。它有很多选项(如简单的ISO8601,RFC3339和许多其他格式支持),更好的性能,并倾向于产生更简单的代码。