我正试图从EDOCX1的值(0)中减去一个日期值,以计算出某物在多久以前。但它抱怨:
1
| TypeError: can't subtract offset-naive and offset-aware datetimes |
值datetime.today()似乎不"知道时区",而我的另一个日期值是。如何获得时区感知的datetime.today()值?现在它给了我当地时间,正好是太平洋标准时间,也就是UTC-8小时。最坏的情况是,我是否可以手动将时区值输入到由datetime.today()返回的datetime对象中,并将其设置为UTC-8?当然,理想的解决方案是自动知道时区。
- 相关:如何获取给定时区的UTC时间"午夜"?
- 似乎我们可以使用datetime.now().astimezone(),因为python 3.6
在标准库中,没有跨平台的方法可以在不创建自己的时区类的情况下创建感知时区。
在Windows上有win32timezone.utcnow(),但这是pywin32的一部分。我宁愿建议使用PYTZ库,它有一个经常更新的大多数时区数据库。
使用本地时区可能非常困难(请参阅下面的"进一步阅读"链接),因此您可能希望在整个应用程序中使用UTC,尤其是对于计算两个时间点之间的差异等算术操作。
您可以这样获得当前日期/时间:
1 2 3
| import pytz
from datetime import datetime
datetime.utcnow().replace(tzinfo=pytz.utc) |
记住,datetime.today()和datetime.now()返回本地时间,而不是UTC时间,因此对它们应用.replace(tzinfo=pytz.utc)是不正确的。
另一个很好的方法是:
稍微短一点,效果也一样。
进一步阅读/观察为什么在许多情况下更喜欢UTC:
- PYTZ文件
- 每个开发人员都应该了解的关于时间的信息——许多实际用例的开发提示
- 时间和时区的问题-计算机爱好者-有趣的、令人大开眼界的关于使用时区的复杂性的解释(视频)
- 用datetime.now(pytz.utc)代替datetime.utcnow().replace(tzinfo = pytz.utc)怎么样?
- @尤米罗:是的,那也行。我会把它加到答案里。谢谢
- 最后,我通过执行d1.replace(tzinfo=None)删除了意识日期中的时区意识,然后使用datetime.utcnow()获取当前的UTC时间,然后我可以正确地减去这两次。不过,Pytz似乎很容易使用。在不久的将来,我可能会转移到这一点上,以便在应用程序中具有更大的灵活性。谢谢!:)
- @盗贼:事实上,消除时区意识没有多大意义。python能够减去两个已知的datetime实例。如果使用多个不同的时区,删除时区信息可能会给出错误的结果。
- 是的,我确保只使用UTC时间:)。当然,让他们知道这一点当然更好,而且我很可能很快就会转移到这一点上。这正是我在看到你的答案之前所做的工作。
- now(utc)今天不返回(除非UTC为午夜),它以UTC返回当前时间。你还需要.replace(hour=0, minute=0, ...)来开始一天的工作(比如datetime.today())
- 文件上说,today()返回的是当前时间,而不是午夜。如果有需要午夜的用例,则需要相应地进行替换。因为最初的问题是关于日期时间差异,所以我认为不需要午夜。
- @andidog:我的评论暗示我(错误地)认为datetime.today()是combine(date.today(), time())。datetime有.now()和.today()两种方法(正如您正确指出的那样)返回(几乎)相同的东西。没有date.now()方法。date和datetime物体不能互换。使用datetime对象而不是date对象会产生细微的错误;如果datetime.today()是datetime.now()的近似副本,我看不出它存在的任何原因。
- 除此之外,如果您碰巧使用django,请始终使用timezone.now(),而不是datetime.now(),因为如果USE_TZ = True,它将自动使用UTC。timezone位于django.utils.timezone处,文档:docs.djangoproject.com/en/1.11/topics/i18n/timezones
- @mre,你的编辑是胡说八道的,结果不是"错误的"(sic)。如果我在洛杉矶时间工作,并且在时间为晚上10点的日期时间中加上90天,那么我得到时间为晚上10点的日期时间,即使我跨越了夏令时边界。这就是在当地时间工作的全部要点;例如,如果我正在为洛杉矶的一家俱乐部创造会议时间,那么结果就是有意义的。是否存在不可取的情况?当然。但是,如果我在使用本地化时区进行算术运算,那是因为我明确需要这种行为。
- @如果我是你,我会回滚MRE的编辑;正如我在我上面的评论中所指出的,我认为这完全没有意义,它只是准确地显示了你所期望的行为,同时在没有解释的情况下宣布它是"错误的"。但这是你的答案,你在这里仍然很活跃,所以我把选择权留给你。
- @Markamery可能在您的用例中不是"错误的",增加了天数。但是试着增加时间,通常这不是你想要的。所以是的,这取决于用例。我的编辑是指出使用简单的时间增量和通过UTC之间的区别。这里有两种方法。用一个适合你的。
- @Markamery我编辑了答案,所以更清楚了。我希望这更适合你
- 我已经替换了重新添加和编辑的整个块,因为1)它包含无效的python提示语法,2)不可重复的输入值(现在)和3)您只描述了一种情况,即时区感知与UTC之间的关系,而Internet上现有的源太多,我们可以参考这些源来获得对整个上下文的很好的解释。还有更多的问题案例。最后,OP只询问了如何创建一个时区感知的日期时间对象,因此最好使用简短的提示/链接,而不是将大于60%的答案专用于另一个问题。
- "每个开发人员都应该知道的时间"链接现在重定向到windward的主页,内容与此相同吗?blogs.windwardreports.com/davidt/2009/11/…
- @阿丹帕金,谢谢你的提醒!由于您建议的博客文章只部分匹配内容,所以我用一个Web存档链接替换了它。
获取特定时区中的当前时间:
1 2 3
| import datetime
import pytz
my_date = datetime.datetime.now(pytz.timezone('US/Pacific')) |
- 看到这个。
- 你不应该使用localized时代除了为输出。多的事情走错的时候用-为基础的日期时间:简单的timedelta并不是把白天节能中的帐户,除非你是在UTC时间开始与。总是使用-意识的基于UTC。convert到当地的-在输出的时候,需要。
- 重申我之前在接受答案的评论中与@mre的意见不一致:使用本地化日期时间是完全合理的理由,"除了输出,不应使用本地化时间"是过于宽泛的建议。假设你在一个夏时制边界前几个小时给日期时间加上1天,在这个边界上时钟会后退一个小时。你想要什么结果?如果您认为时间应该相同,请使用本地化日期时间。如果您认为应该早一小时,请使用UTC或时区naive日期时间。这是有意义的领域依赖。
- @只要我同意,你可能想增加或减少一些天或小时,而不关心时区问题(如你的例子),这个评论与传递时区修正时间给客户有关。由于python主要用于后端进程,所以它将时间传递给客户机。服务器应该总是以UTC格式传递日期/时间,客户机应该将其转换为自己的本地日期/时间/时区,否则会发生不好的事情:只需检查EDOCX1的输出(0),看看这是否是您所期望的。
- en.wikipedia.org/wiki/local_mean_时间
- "服务器应始终以UTC格式传递日期/时间,客户机应将其转换为自己的本地日期/时间/时区"-不,这并非普遍正确。有时使用客户机的时区是不合适的,需要将适当的时区作为数据的一部分进行传输。如果作为伦敦人,我在他们的网站上看到旧金山象棋俱乐部的会议时间,我应该在旧金山时间,而不是在伦敦时间看到他们。
- @mre(至于datetime.datetime(2016, 11, 5, 9, 43, 45, tzinfo=pytz.timezone('US/Pacific')),是的,这是python的datetimeAPI的一个可怕的陷阱。对于任何想知道wtf是否能得出结果的人,答案是datetime构造函数的tzinfo参数对于pytz时区只是简单的中断;您需要使用时区的.localize()方法来创建时区感知的日期时间。)
- "如果作为伦敦人,我在他们的网站上看到旧金山象棋俱乐部的会议时间,我应该在旧金山时间,而不是在伦敦时间看到他们。"那么,不要使用时区、UTC或任何东西,你只需要天真的约会时间。
在Python3中,标准库使指定UTC作为时区变得更容易:
1 2 3
| >>> 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的答案。
下面是一个同时在python 2和3上工作的stdlib解决方案:
1 2 3 4
| 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对象(来自文档的示例):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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偏移量的时区,获得午夜更为复杂。
构造表示当前时间的时区感知日期时间对象的另一种方法:
1 2 3 4
| import datetime
import pytz
pytz.utc.localize( datetime.datetime.utcnow() ) |
- 注意,pytz.utc和pytz.utc都是定义的(并且是相同的)。
- 这个答案比公认的答案更好,因为它更为普遍:replace()ing时区在大多数其他用途中通常容易出错,而localize()ing是将时区分配给原始时间戳的首选方式。
- @AntonyHatchkins:.localize()方法对于不明确的本地时间(非UTC输入)失败。@Philfreo使用.now(pytz_timezone)的答案在这种情况下仍然有效。
- 正如python docs中指定的那样,.now(pytz_timezone)与localize(utcnow)的作用完全相同——首先它以UTC生成当前时间,然后它为它分配一个时区:"<…>在这种情况下,结果相当于tz.fromutc(datetime.utcnow().replace(tzinfo=tz))"。两个答案都是正确的,而且总是有效的。
- 唯一可以安全地让时区知道的幼稚(非UTC)时间是:底层系统应该知道UTC值,而通过olson db的pytz应该知道如何将其转换为世界上的任何时区。由于夏令时的模糊性,很难让任何其他幼稚(非UTC)时区意识到这一点。这不是.localize的问题(给它输入is_dst的值可以使它在任何日期都有效)。这是日光节约实践中固有的问题。
- @安东尼哈金斯错了。如果不理解.localize(now)失败的原因,请另问一个问题。
- 更具体一点
- 或者,如果您不理解为什么对于非UTC日期,localize优于replace,请单独问一个问题。
- @安东尼哈金斯:如果你想像我一样通知我你的评论,就用@..。怎么了:1。pytz.utc.localize()比.replace(tzinfo=pytz.utc)好,错了2。non_utc_tz.localize(utcnow)比.now(non_utc_tz)好--不对。看看你的第一和第二条评论。
- @J.F.塞巴斯蒂安错了。如果你给它正确的is_dst参数,localize不会因为不明确的时间日期(非UTC输入)而失败。看看你的第一条评论。pytz.utc.localize()与.replace(tzinfo=pytz.utc)的做法完全相同——这不是我的观点。如果你重复一件同样的错误的事情上百万次,它不会因此变得更正确。
- 另外,non_utc_tz.localize(utcnow)与.replace(tzinfo=pytz.utc)的作用完全相同。我认为没有必要为此争论。
- antonyhatchkins @:我会remind你:quesiton"-我知道datetime.today()"。事实:datetime.now(tz)工程没有specifying is_dstparameter。事实:.replace(tzinfo=pytz.utc)工程为UTC -。事实:tz.localize(now)失败可能为非timezones UTC。你可以用disambiguate is_dst(为一些timezones,它的作品只在最近版本),但你怎么找到了is_dstprogrammatically怎样?conslusion:.now(tz)的更好的选项比tz.localize(now, is_dst=is_dst)睾丸(你可以用.replace(tzinfo=pytz.utc)性能为理由,如果你的轮廓,所以说)。
- @塞巴斯蒂安:我会remind你:我不suggest non_utc_tz.localize(non_utc_now, is_dst=is_dst)T。是的,你说的话。事实上:你的结论并不没有什么要做什么,我说。
- 让我repeat点:我的两个replace和localize可以用来为assigning的时区的到的naive timestamp。这两个工作identically当操作是unambiguous。但如果分配也ambiguous localize也更好的因为它会警告你关于它到爱丽丝的一个例外,你可以抓住,然后重新运行它与是的先生也_ DST value如果你知道它(你可以问一个端用户-例如)或arbitrary价值给你50:50的机会的权利猜一猜。replace上另一方面会给同样的50%的机会之权利,但它想通知你关于ambiguity韩元。
- 另有)同意所有的事实。我也datetime.now(pytz.utc)找到最好的方式来做它。
- plz评论我的新到这个问题的答案。
- antonyhatchkins @:错了。.replace()可能为任何失败-,让我在不同的UTC对胶印在过去甚至如果一个结果,也unambiguous。总是使用.localize()代替.replace()为timezones与非固定对胶印:UTC日期时间转换-使用pytz
- @塞巴斯蒂安最后你让我我的点("localize(衬衫)的优先股的方式为assigning -到naive timestamps")。是的,我同意,你已经错了,从一开始的。一年真的不是很长,为这样一个问题formidable);
- antonyhatchkins @:错了。你的观点:".now(pytz _ -)并到底同样的年代localize(utcnow)"仍然是错误的。我的reread carefully评论的时间。
- @塞巴斯蒂安你*不能承认你已经被错误的所有的时间吗?平静下来,我的reread评论carefully和停止spamming亩。
- antonyhatchkins @:你不能被提供的单一statement从我的评论是错误的。如果你继续到后incorrect statements;我可能继续refute到他们。它看起来像它在你的pointless案例,但我会继续做它,所以,你就不会被misled其他人。
- @塞巴斯蒂安你似乎喜欢长期的conversations。我会回答你在一年。没有人会读的谈话…这长,这pointless反正。??我问你停止spamming我吗?
如果使用django,则可以设置不知道TZ的日期(仅限UTC)。
在settings.py中注释以下行:
- 在这个问题中,你在哪里看到姜戈提到的?
- 现在我只想爬到岩石下死去。
- "non-tz-aware"并不能神奇地使日期只在UTC
下面是用stdlib生成它的一种方法:
1 2 3 4 5
| 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时区的日期,因此,如果需要确定生成日期的时区,可以使用此解决方案。在本例和本地时区中:
1 2 3 4 5
| date
datetime.datetime(2017, 8, 1, 12, 15, 44, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)))
date.tzname()
'UTC+02:00' |
关键是将%z指令添加到表示格式中,以指示生成的时间结构的UTC偏移量。可以在日期时间模块文档中查询其他表示格式。
如果需要UTC时区的日期,可以将time.localtime()替换为time.gmtime()。
1 2 3 4 5 6 7
| 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"的错误指令
- 你在python 2上,对吗?不幸的是,z指令在python 2上似乎不可用。_ strptime.py代码
pytz是一个python库,它允许使用python 2.3或更高版本进行准确的跨平台时区计算。
对于stdlib,这是不可能的。
在So上看到类似的问题。
为什么不使用这里描述的dateutil:http://joelinoff.com/blog/?P=802
1 2 3
| from dateutil.tz import tzlocal
# Get the current date/time with the timezone.
now = datetime.datetime.now(tzlocal()) |
- 请参阅J.F.Sebastian的回答,了解这种情况会产生不正确的结果。
- 我认为另一篇文章中的错误只与特定的用例相关。tzlocal()函数仍然是最简单的解决方案之一,应该在这里明确提及。
您可以使用datetime通过解析使用%z指令(在python 3.3中引入)的time.strftime调用的输出来创建本地timezone,如jcazor所示。您可以使用该timezone创建一个带有一行程序的已知datetime实例:
1 2 3 4 5 6 7 8
| 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 |
在utc时区中获得一个时区感知日期就足够进行日期减法了。
但是,如果您希望在当前时区中有一个时区感知日期,那么可以使用tzlocal:
1 2 3
| from tzlocal import get_localzone # pip install tzlocal
from datetime import datetime
datetime.now(get_localzone()) |
ps dateutil具有类似的功能(dateutil.tz.tzlocal)。但是,尽管共享这个名字,它有一个完全不同的代码库,正如J.F.Sebastian指出的那样,这可能会产生错误的结果。
- python通常用于服务器。服务器上的本地时区通常是无意义的,应始终设置为UTC。以这种方式设置datetime tzinfo在某些情况下会失败。最好使用UTC,然后只在输出时本地化到所需时区。例如,任何时间增量计算都不考虑夏令时,因此这些计算应该在UTC中完成,然后本地化。
- @MRE错误,主题外,例子?
- 尝试使用在观察日光节约的时区中本地化的日期时间对象,添加若干天以更改日光节约状态,您将看到在本地化时区中对日期时间对象的操作失败,并且不尊重日光节约。因此,我认为您应该始终以UTC时间执行任何日期时间操作。
- 要点是:不要这样做,在UTC中执行操作,然后使用datetime.astimezone(timezone)在输出时转换为本地时区。
我将此答案添加为经常使用非UTC时区的人。
唯一有自己方法的时区是timezone.utc,但是如果需要,可以使用timedelta&timezone,并强制使用.replace,使用任何UTC偏移来修改时区。
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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))作为时区是这里真正的银弹,它还有许多其他有用的应用。
对时区感知日期时间使用如下所示的时区,默认值为UTC:
1 2
| from django.utils import timezone
today = timezone.now() |
如果在python中得到当前的时间和日期,那么在python中导入日期和时间,之后pytz包将得到当前的日期和时间,比如……
1 2 3 4
| from datetime import datetime
import pytz
import time
str(datetime.strftime(datetime.now(pytz.utc),"%Y-%m-%d %H:%M:%S%t")) |
在我看来,另一个更好的选择是使用Pendulum而不是pytz。考虑以下简单代码:
1 2 3 4 5 6
| >>> import pendulum
>>> dt = pendulum.now().to_iso8601_string()
>>> print (dt)
2018-03-27T13:59:49+03:00
>>> |
要安装摇锤并查看其文档,请转到此处。它有很多选项(如简单的ISO8601、RFC339和许多其他格式支持),性能更好,并且往往产生更简单的代码。
- 不知道为什么在这里投票,这个代码在多个为我运行7/24的程序中工作:)。我不介意其他意见,但请告诉我为什么它对你不起作用,让我检查一下。提前谢谢