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

min*_*ief 277 python timezone datetime date

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

TypeError: can't subtract offset-naive and offset-aware datetimes
Run Code Online (Sandbox Code Playgroud)

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

And*_*Dog 331

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

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

使用本地时区可能非常棘手(请参阅下面的"进一步阅读"链接),因此您可能更愿意在整个应用程序中使用UTC,尤其是算术运算,如计算两个时间点之间的差异.

您可以像这样获得当前日期/时间:

import pytz
from datetime import datetime
datetime.utcnow().replace(tzinfo=pytz.utc)
Run Code Online (Sandbox Code Playgroud)

请注意datetime.today()datetime.now()返回当地时间,而不是UTC时间,因此应用.replace(tzinfo=pytz.utc)它们是不正确的.

另一个好方法是:

datetime.now(pytz.utc)
Run Code Online (Sandbox Code Playgroud)

这有点短,并做同样的事情.


在许多情况下进一步阅读/观看为什么更喜欢UTC:

  • 怎么样`datetime.now(pytz.utc)`而不是`datetime.utcnow().replace(tzinfo = pytz.utc)`? (72认同)
  • 在python3中你可以简单地使用“datetime.now(timezone.utc)” (11认同)
  • `now(utc)`今天没有返回(除非它是UTC的午夜),它以UTC返回当前时间.你还需要[`.replace(hour = 0,minute = 0,...)`来获取当天的开头(比如`datetime.today()`)](http://stackoverflow.com/a/ 4279分之25421145) (3认同)
  • 添加到这个答案,如果您碰巧使用django,请始终使用`timezone.now()`而不是`datetime.now()`,因为如果`USE_TZ = True`它将自动使用UTC.`timezone`位于`django.utils.timezone`,文档:https://docs.djangoproject.com/en/1.11/topics/i18n/timezones/ (3认同)

phi*_*reo 97

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

import datetime
import pytz
my_date = datetime.datetime.now(pytz.timezone('US/Pacific'))
Run Code Online (Sandbox Code Playgroud)

  • 重申对@MrE的不同意见,我之前在接受的答案的评论中表示:有充分合理的理由使用本地化的日期时间和*"你不应该使用除输出之外的本地化时间"*是过于宽泛的建议.假设您在夏令时边界前几小时向日期时间添加1天,时钟可以延迟一小时.你想要什么结果?如果您认为时间应该相同,请使用本地化的日期时间.如果您认为它应该提前一小时,请使用UTC或timezone-naive日期时间.哪个有意义依赖于域. (4认同)
  • 参见[this](https://github.com/newvem/pytz/blob/f137ff00112a9682bc4e4945067b3b88f158d010/pytz/tzinfo.py#L192-L193)。 (2认同)
  • 除了输出之外,您不应该使用本地化时间。使用基于时区的日期时间时,很多事情都会出错:一个简单的 timedelta 不会考虑夏令时,除非您开始使用 UTC 时间。始终使用基于 UTC 的时区感知。需要时在输出时转换为本地时区。 (2认同)
  • *“服务器应始终以 UTC 格式传递日期/时间,客户端应将其转换为自己的本地日期/时间/时区”* - 不,这并非普遍适用。有时使用客户端的时区是不合适的,需要将合适的时区作为数据的一部分进行传输。如果作为伦敦人,我在他们的网站上查看旧金山国际象棋俱乐部的会议时间,我应该在旧金山时间看到它们,而不是在伦敦时间。 (2认同)

Fli*_*imm 58

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

>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2016, 8, 26, 14, 34, 34, 74823, tzinfo=datetime.timezone.utc)
Run Code Online (Sandbox Code Playgroud)

如果您想要一个仅使用标准库并且在Python 2和Python 3中都有效的解决方案,请参阅JF Sebastien的答案.

  • @Torxed 这太有趣了。这会给你一个固定的偏移时区。我更喜欢使用与“America/Los_Angeles”等位置或政治区域相关的时区,因为后者考虑了夏令时。 (2认同)

jfs*_*jfs 18

这是一个适用于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
Run Code Online (Sandbox Code Playgroud)

其中today是一个表示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()
Run Code Online (Sandbox Code Playgroud)

相关:对于给定的UTC时间,获得午夜(一天开始)几种方法的性能比较.
注意:对于具有非固定utc偏移的时区来说,午夜时间更复杂.


Dar*_*zak 14

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

import datetime
import pytz

pytz.utc.localize( datetime.datetime.utcnow() )  
Run Code Online (Sandbox Code Playgroud)

  • 这个答案比被接受的答案更好,因为它更通用:`replace()`timezone在大多数其他用途中通常容易出错,而`localize()`ing是将时区分配给天真时间戳的首选方式. (2认同)

laf*_*ste 9

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

在settings.py中注释以下行:

USE_TZ = True
Run Code Online (Sandbox Code Playgroud)

  • 现在我只想在岩石下爬行而死. (30认同)
  • 你在哪里看到这个问题中提到的django? (6认同)
  • 某个善良的灵魂删除了我之前的评论,在这里道歉,所以再次:对我来说很羞耻,错误的答案,因为这个问题不是特定于 Django 的。我留下它是因为无论如何它可能会帮助一些用户,但当分数接近 0 时我会删除它。如果这个答案不合适,请随意投反对票。 (3认同)

MrF*_*pes 9

应该强调的是,从 Python 3.6 开始,您只需要标准库即可获取代表本地时间(操作系统设置)的时区感知日期时间对象。使用astimezone()

\n
import datetime\n\ndatetime.datetime(2010, 12, 25, 10, 59).astimezone()\n# e.g.\n# datetime.datetime(2010, 12, 25, 10, 59, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), \'Mitteleurop\xc3\xa4ische Zeit\'))\n\ndatetime.datetime(2010, 12, 25, 12, 59).astimezone().isoformat()\n# e.g.\n# \'2010-12-25T12:59:00+01:00\'\n\n# I\'m on CET/CEST\n
Run Code Online (Sandbox Code Playgroud)\n

(参见@johnchen902的评论)。

\n

但请注意,有一个小警告,不要指望 timedelta 时区有任何“DST 意识”。

\n


Mih*_*otă 7

从Python 3.3开始,仅使用标准库的单行代码就可以使用。您可以datetime使用来获取本地时区感知对象astimezone(如johnchen902建议):

from datetime import datetime, timezone

aware_local_now = datetime.now(timezone.utc).astimezone()

print(aware_local_now)
2019-08-02 11:26:32.341817-07:00
Run Code Online (Sandbox Code Playgroud)

  • 该文档很有帮助,可以在这里找到:https://docs.python.org/3.8/library/datetime.html#datetime.datetime.astimezone。这个令人难以置信的基本功能被深深地埋在文档中一个不起眼的段落中,因此这个 stackoverflow 答案实际上是整个互联网上唯一包含此信息的地方。在文档中还可以看出,从Python 3.6开始,可以在不带任何参数的情况下调用“datetime.now()”并返回正确的本地结果(天真的“datetime”被假定为本地时区) 。 (2认同)
  • 这里不需要将“timezone.utc”传递给“now”,您只需运行“datetime.datetime.now().astimezone()”即可 (2认同)
  • @SauravKumar,这不是原来的问题。尝试“datetime.now(timezone.utc)”。 (2认同)

use*_*312 6

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

使用stdlib,这是不可能的.

SO上看到类似的问题.


jca*_*zor 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)
Run Code Online (Sandbox Code Playgroud)

date将存储本地日期和UTC偏移量,而不是UTC时区的日期,因此如果需要确定生成日期的时区,则可以使用此解决方案.在此示例中和我当地时区:

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

date.tzname()
'UTC+02:00'
Run Code Online (Sandbox Code Playgroud)

关键是将%z指令添加到表示FORMAT,以指示生成的时间结构的UTC偏移.其他表示格式可以在datetime模块文档中查阅

如果您需要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'
Run Code Online (Sandbox Code Playgroud)

编辑

这仅适用于python3.z指令在python 2 _strptime.py代码上不可用


G. *_*ühr 5

使用可识别时区的Python datetime.datetime.now()中所述的dateutil :

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

  • 请参阅 JF Sebastian 的 [this answer](http://stackoverflow.com/questions/13218506/how-to-get-system-timezone-setting-and-pass-it-to-pytz-timezone) 了解这种情况给出不正确的结果。 (2认同)
  • 我认为另一篇文章中的错误仅与特定用例有关。tzlocal()函数仍然是最简单的解决方案之一,在这里一定要提及。 (2认同)