datetime.today()
的值中减去一个日期值,以计算多久以前发生的事情。但是它抱怨:TypeError: can't subtract offset-naive and offset-aware datetimes
datetime.today()
的值似乎不是“时区感知”的,而我的其他日期值是。我如何获取知道时区的datetime.today()
值?现在,这给了我当地时间,该时间是PST,即UTC-8小时。最坏的情况是,有没有办法我可以在
datetime
返回的datetime.today()
对象中手动输入时区值并将其设置为UTC-8?当然,理想的解决方案是让它自动知道时区。
#1 楼
在标准库中,没有跨平台的方法可以在不创建自己的时区类的情况下创建可感知的时区。在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文档
每个开发人员应了解的时间-许多实际用例的开发提示
时间问题与时区-Computerphile –有趣的,令人大开眼界的说明关于使用时区的复杂性的国家(视频)
评论
怎么样datetime.now(pytz.utc)代替datetime.utcnow()。replace(tzinfo = pytz.utc)?
–eumiro
2010-12-25 15:24
now(utc)今天不返回(除非在UTC是午夜),它以UTC返回当前时间。您还需要.replace(hour = 0,minutes = 0,...)来获取一天的开始时间(例如datetime.today())
– jfs
2014年8月21日在8:05
文档说,today()返回当前时间,而不是午夜。如果存在需要午夜使用的情况,是的,需要相应地进行更换。由于最初的问题是关于日期时间差异的,所以我认为不需要午夜。
– AndiDog
2014年8月21日13:42
@AndiDog:我的评论暗示(错误地)我认为datetime.today()是Combine(date.today(),time())。 datetime同时具有.now()和.today()方法(正如您正确指出的),它们返回(几乎)相同的东西。没有date.now()方法。日期和日期时间对象不可互换。使用datetime对象而不是date对象会产生细微的错误。我认为datetime.today()存在几乎与datetime.now()几乎相同的任何原因。
– jfs
2014年8月24日在23:28
此外,如果您碰巧正在使用django,请始终使用timezone.now()而不是datetime.now(),因为如果USE_TZ = True,它将自动使用UTC。时区位于django.utils.timezone,文档:docs.djangoproject.com/en/1.11/topics/i18n/timezones
–瑞安
17年8月4日在3:05
#2 楼
获取特定时区的当前时间:请记住先安装
pytz
。评论
看到这个。
– Wim
17年6月6日在16:58
您不应该使用本地化时间(输出除外)。使用基于时区的日期时间时,很多事情都会出错:一个简单的timedelta不会考虑夏令时,除非您开始使用UTC时间。始终使用基于UTC的时区感知。必要时将输出转换为本地时区。
– Mr
17年9月13日在18:36
要重申与@MrE的不同意见,我之前已经在接受的答案的评论中表达过:有完全正当的理由使用本地化的日期时间,并且“除输出外,您不应该使用本地化的时间”是过于广泛的建议。假设您在夏令时边界之前的几个小时向日期时间添加1天,时钟将在该时间上倒退一个小时。您想要什么结果?如果您认为时间应该相同,请使用本地化的日期时间。如果您认为应该早一个小时,请使用UTC或未使用时区的日期时间。有意义的是取决于域的。
–马克·阿默里(Mark Amery)
18年1月31日在14:42
我完全同意@MarkAmery,您可能想添加或减去几天或几个小时,而不关心时区问题(例如您的示例),此注释与将时区校正后的时间传递给客户端有关。由于Python主要用于后端进程,因此它将时间传递给客户端。服务器应始终以UTC传递日期/时间,而客户端应将其转换为自己的本地日期/时间/时区,否则会发生不好的事情:只需检查datetime.datetime(2016,11,5,9,43, 45,tzinfo = pytz.timezone('US / Pacific'))看看是否正是您所期望的
– Mr
18年1月31日在22:46
“服务器应始终以UTC传递日期/时间,而客户端应将其转换为自己的本地日期/时间/时区”-不,这并非普遍如此。有时使用客户端的时区不合适,因此需要将适当的时区作为数据的一部分进行传输。如果作为伦敦人,我在他们的网站上查看了旧金山国际象棋俱乐部的开会时间,那么我应该在旧金山时间而不是伦敦时间看到他们。
–马克·阿默里(Mark Amery)
18年1月31日在22:57
#3 楼
在Python 3.2+中:datetime.timezone.utc
:标准库使将UTC指定为时区变得更加容易:
>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2020, 11, 27, 14, 34, 34, 74823, tzinfo=datetime.timezone.utc)
您还可以使用
astimezone
获得包含本地时间偏移量的日期时间: >>> datetime.datetime.now(datetime.timezone.utc).astimezone()
datetime.datetime(2020, 11, 27, 15, 34, 34, 74823, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))
(在Python 3.6+中,您可以将最后一行缩短为:
datetime.datetime.now().astimezone()
)如果您想要一个仅使用标准库并且在Python 2和Python 3中都可以使用的解决方案,请参阅jfs的答案。
在Python 3.9+中:
zoneinfo
以使用IANA时区数据库:在Python 3.9中,您可以使用标准库通过
zoneinfo
来指定特定时区,如下所示:>>> from zoneinfo import ZoneInfo
>>> datetime.datetime.now(ZoneInfo("America/Los_Angeles"))
datetime.datetime(2020, 11, 27, 6, 34, 34, 74823, tzinfo=zoneinfo.ZoneInfo(key='America/Los_Angeles'))
zoneinfo
从操作系统或第一方PyPI软件包tzdata
(如果有)中获取时区数据库。#4 楼
从Python 3.3开始,仅使用标准库的单行代码就可以使用。您可以使用datetime
(由johnchen902建议)获取本地时区感知的astimezone
对象:from datetime import datetime, timezone
aware_local_now = datetime.now(timezone.utc).astimezone()
print(aware_local_now)
# 2020-03-03 09:51:38.570162+01:00
print(repr(aware_local_now))
# datetime.datetime(2020, 3, 3, 9, 51, 38, 570162, tzinfo=datetime.timezone(datetime.timedelta(0, 3600), 'CET'))
评论
该文档对您有很大帮助,可在以下位置找到:docs.python.org/3.8/library/…。这个令人难以置信的基本功能嵌入在文档中一个晦涩的段落中,因此该stackoverflow答案实际上是拥有此信息的整个互联网上唯一的地方。在文档中,还可以看到,由于Python 3.6,可以不带任何参数调用datetime.now()并返回正确的本地结果(假定原始日期时间位于本地时区)。
–atimholt
20-2-8在3:25
这里不需要将timezone.utc传递到现在,您只需运行datetime.datetime.now()。astimezone()
– Flimm
20-09-16在7:55
@Flimm,如果要支持Python <3.6,则需要它。
– MihaiCapotă
20 Sep 16 '21:34
str(datetime.now(timezone.utc).astimezone())->'2020-09-18 19:19:33.508176 + 05:30'|有什么办法可以获取带有UTC时区的日期对象?它始终将时区指定为IST。我不想使用其他任何python库,例如pytz
– Saurav Kumar
20 Sep 18 '13:51
@SauravKumar,这不是原始问题。尝试datetime.now(timezone.utc)。
– MihaiCapotă
20-09-18在17:07
#5 楼
这是一个可在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对象(来自文档的示例):相关信息:在给定UTC时间获得午夜(一天的开始)的几种方法的性能比较。 请注意:要获取具有非固定UTC偏移量的时区的午夜,这会更复杂。
#6 楼
另一种构造表示当前时间的时区感知日期时间对象的方法:import datetime
import pytz
pytz.utc.localize( datetime.datetime.utcnow() )
可以通过运行以下命令从PyPI安装
pytz
:$ pipenv install pytz
评论
请注意,pytz.utc和pytz.UTC都已定义(并且相同)
– drevicko
13年2月28日在23:36
这个答案比公认的要好,因为它更通用:在大多数其他用途中,replace()ing timezone通常容易出错,而localize()ing是将时区分配给朴素时间戳的首选方法。
– Antony Hatchkins
2014年9月17日下午4:59
@AntonyHatchkins:.localize()方法在不明确的本地时间(非UTC输入)失败。在这种情况下,使用.now(pytz_timezone)的@philfreo答案仍然有效。
– jfs
15年4月18日在18:40
如python文档中所指定,.now(pytz_timezone)与localize(utcnow)完全相同-首先,它以UTC生成当前时间,然后为其分配时区:“ <...>在这种情况下,结果等于tz.fromutc(datetime.utcnow()。replace(tzinfo = tz))”。这两个答案都是正确的,并且始终有效。
– Antony Hatchkins
2015年4月19日在8:20
现在可以安全地使时区知道的唯一幼稚(非UTC)时间是:底层系统应该知道UTC值,而通过OLSON db的pytz应该知道如何将其转换为世界上的任何时区。由于夏令时期间的模棱两可,因此很难让其他任何天真的(非UTC)时区都知道。这不是.localize的问题(向它提供is_dst值可使其在任何日期均可工作)。这是夏时制实践的固有问题。
– Antony Hatchkins
2015年4月19日在8:36
#7 楼
如果您使用的是Django,则可以设置非tz格式的日期(仅UTC)。在settings.py中注释以下行:
USE_TZ = True
评论
您在哪里看到这个问题中提到的django?
– vonPetrushev
13年7月30日在15:22
某种友善的灵魂在这里删除了我之前的评论道歉,因此再次:羞愧于我,答案错误,因为问题不是特定于Django的。我离开它是因为它仍然可以帮助某些用户,但是当分数接近0时,我将其删除。如果此答案不合适,请随时投票。
– laffuste
20年1月14日,下午3:26
#8 楼
按照时区感知的Python datetime.datetime.now()中所述使用dateutil:from dateutil.tz import tzlocal
# Get the current date/time with the timezone.
now = datetime.datetime.now(tzlocal())
评论
遇到错误结果的情况,请参阅塞巴斯蒂安·J·F的答案。
– Antony Hatchkins
15年4月29日在18:01
我认为另一篇文章中的错误仅与特定用例有关。 tzlocal()函数仍然是最简单的解决方案之一,在这里一定要提及。
–user8162
18-10-8在15:28
#9 楼
pytz是一个Python库,它允许使用Python 2.3或更高版本进行准确的跨平台时区计算。使用stdlib,这是不可能的。
在SO上看到类似的问题。
#10 楼
这是使用stdlib生成它的一种方法:import time
from datetime import datetime
FORMAT='%Y-%m-%dT%H:%M:%S%z'
date=datetime.strptime(time.strftime(FORMAT, time.localtime()),FORMAT)
date将存储本地日期和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偏移量。其他表示形式可以在datetime模块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代码上不可用
评论
ValueError:'z'是格式为'%Y-%m-%dT%H:%M:%S%z'的错误指令
– jno
17年6月22日在10:16
您使用的是python 2,对吗?不幸的是,似乎z指令在python 2上不可用。_strptime.py代码
– jcazor
17年6月23日在21:03
#11 楼
应该强调的是,从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)可以提供已知的日期时间,却不知道DST。
#12 楼
在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·塞巴斯蒂安(J.F. Sebastian)指出的那样,可能会产生错误的结果。评论
python通常在服务器上使用。服务器上的本地时区通常没有意义,应始终设置为UTC。在某些情况下,以这种方式设置datetime tzinfo会失败。最好使用UTC,然后仅在输出时定位到所需的时区。例如,任何timedelta计算都不会考虑夏令时,因此应在UTC中进行,然后进行本地化。
– Mr
17年9月13日在18:34
@MrE错误的题外话吗?
– Antony Hatchkins
17年9月15日下午5:02
尝试使用在时区本地化的datetime对象观察夏时制,增加天数以更改夏时制状态,您会发现对本地化时区中的datetime对象进行操作会失败并且将不遵守夏时制。因此,我的评论是您应该始终在UTC时间执行任何datetime操作。
– Mr
17/09/15在5:07
重点是:不要这样做,请在UTC中进行操作,然后使用datetime.astimezone(timezone)转换为输出时的本地时区。
– Mr
17年9月15日在5:10
#13 楼
这是一个使用可读时区的解决方案,该解决方案适用于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
#14 楼
我认为更好的另一种选择是使用Pendulum
而不是pytz
。考虑以下简单代码:>>> import pendulum
>>> dt = pendulum.now().to_iso8601_string()
>>> print (dt)
2018-03-27T13:59:49+03:00
>>>
要安装Pendulum并查看其文档,请转到此处。它具有大量选项(例如简单的ISO8601,RFC3339和许多其他格式支持),更好的性能并倾向于产生更简单的代码。
评论
不知道为什么在这里投票,这段代码在为我运行7/24的多个程序中起作用:)。我并不介意其他意见,但是请允许我检查一下为什么它对您不起作用。提前致谢
– ng10
19年3月16日在17:06
这是一个很好的建议,在像日期时间操作的可读性和易用性这样的混乱领域中,IMO首先出现。
–Loki
20-10-13在20:00
#15 楼
尤其是对于非UTC时区:唯一具有自己方法的时区是
timezone.utc
,但是如果需要,可以使用timedelta
和timezone
来伪装具有任何UTC偏移量的时区,并使用.replace
。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))
作为时区才是真正的银弹,它还有许多其他有用的应用程序。#16 楼
来自“ howchoo”的泰勒写了一篇非常出色的文章,帮助我更好地了解了日期时间对象,请点击下面的链接使用日期时间
本质上,我只添加了以下内容到我的两个日期时间对象的结尾
.replace(tzinfo=pytz.utc)
示例:
import pytz
import datetime from datetime
date = datetime.now().replace(tzinfo=pytz.utc)
#17 楼
如果您在python中获得了当前时间和日期,则在导入日期和时间后,将在pytz包中输入python的当前日期和时间,如下所示:。from datetime import datetime
import pytz
import time
str(datetime.strftime(datetime.now(pytz.utc),"%Y-%m-%d %H:%M:%S%t"))
#18 楼
如下所示,将时区用于可识别时区的日期时间。默认值为UTC:from django.utils import timezone
today = timezone.now()
#19 楼
请尝试pnp_datetime,所有使用和返回的时间都是时区,并且不会引起任何偏移天然和偏移感知问题。>>> from pnp_datetime.pnp_datetime import Pnp_Datetime
>>>
>>> Pnp_Datetime.utcnow()
datetime.datetime(2020, 6, 5, 12, 26, 18, 958779, tzinfo=<UTC>)
#20 楼
这对我有用,我首先尝试获取UTC
时间,然后根据您要设置的时区来增加或减少小时。today = datetime.utcnow()
评论
相关:如何获取给定时区的“午夜” UTC时间?自Python 3.6起,似乎可以使用datetime.now()。astimezone()了。
谢谢@ johnchen902。您的评论已转换为此处的答案:stackoverflow.com/a/49059780/247696