【问题标题】:Django/python - dispelling confusion regarding dates and timezone-awarenessDjango/python - 消除关于日期和时区意识的混淆
【发布时间】:2016-03-07 09:40:53
【问题描述】:

我一直在 python/django 中广泛使用日期。为了解决各种用例,我一直在盲目地尝试各种不同的方法,直到其中一种方法奏效,却没有了解各种功能背后的逻辑。

现在是关键时刻。我想问几个关于 django/python 中复杂的日期和时区的问题。

如何解释已经有时区的datetime 对象?

为了澄清,假设我做了以下事情:

>>> generate_a_datetime()
datetime.datetime(2015, 12, 2, 0, 0, tzinfo=<DstTzInfo 'Canada/Eastern' LMT-1 day, 18:42:00 STD>)
>>>

控制台输出对我来说似乎模棱两可:

Q1) 这个datetime 对象说是2015-12-02 - generate_a_datetime 函数告诉我什么?是说“一个站在加拿大东部看着他的日历的人看到“2015-12-02”?还是说“这是“2015-12-02 UTC”。 .. 但不要忘记将其调整为加拿大东部时区!”

django.utils.timezone.make_aware 让我很困惑。

例如:

>>> from django.utils import timezone
>>> import pytz
>>> tz = pytz.timezone('Canada/Eastern')
>>> now_unaware = datetime.datetime.now()
>>> now_aware_with_django = timezone.make_aware(now_unaware, tz)
>>> now_aware_with_datetime = now_unaware.replace(tzinfo=tz)
>>> now_unaware
datetime.datetime(2015, 12, 2, 22, 1, 19, 564003)
>>> now_aware_with_django
datetime.datetime(2015, 12, 2, 22, 1, 19, 564003, tzinfo=<DstTzInfo 'Canada/Eastern' EST-1 day, 19:00:00 STD>)
>>> now_aware_with_datetime
datetime.datetime(2015, 12, 2, 22, 1, 19, 564003, tzinfo=<DstTzInfo 'Canada/Eastern' LMT-1 day, 18:42:00 STD>)
>>> 

对象now_aware_with_djangonow_aware_with_datetime 的行为似乎相似,但它们的控制台输出表明它们是不同的。

Q2) now_aware_with_djangonow_aware_with_datetime 有什么区别?

Q3) 我如何知道我需要使用timezone.make_aware 还是datetime.replace

原始日期时间与 UTC 日期时间

UTC 表示时间值没有变化。 “天真”似乎意味着时间没有与之关联的时区。

Q4) 原始日期时间和 UTC 日期时间有什么区别?看起来它们完全一样 - 没有对实际时间值施加任何转换。

Q5) 我如何知道何时要使用原始时间以及何时要使用 UTC 时间?

如果我能得到所有 5 个问题的答案,那就太好了。非常感谢!

【问题讨论】:

    标签: python django datetime pytz


    【解决方案1】:

    Q1) 这个日期时间对象说是 2015-12-02 - generate_a_datetime 函数告诉我什么?是说“一个站在加拿大东部看日历的人看到“2015-12-02”吗?还是说“这是“2015-12-02 UTC”……但不要忘记调整这个到加拿大东部时区!”

    第一个解释是正确的。时区感知的日期时间已经为您“调整”了,而 tzinfo 只是告诉您它指定在哪个时区。

    Q2) now_aware_with_djangonow_aware_with_datetime 有什么区别?

    对于第一种情况,您要创建一个日期时间,它表示与“天真”时间点相同的时间点,并且 假设天真的时间点位于您当地的时区。

    对于第二种情况,您是说天真者已经在您提供的时区中,然后您只需添加 tzinfo。

    Q3) 我如何知道是否需要使用timezone.make_awaredatetime.replace?

    好吧,由于它们做不同的事情,你需要知道你想要做什么才能知道使用哪个。如果您想从一个简单的时区(在您的本地时间)转换为不同的时区,您可以使用make_aware。如果您已经知道您的原始日期时间的时区,您只需使用替换(或查看pytz 中的localize,这对这项任务要更加小心)。

    注意: 通常,如果您一开始就有任何幼稚的日期时间,那么您早先做错了,您应该早点发现它。试着让他们在你的应用程序的边界上意识到 - 我将在 Q5 中详细说明这一点。

    Q4) 原始日期时间和 UTC 日期时间有什么区别?看起来它们完全一样 - 没有对实际时间值施加任何转换。

    一个简单的日期时间只是一个日期时间,它不会告诉你它所在的时区。它不一定是 UTC,它可以是任何东西。它类似于 bytestrings 和 unicode - 你必须知道编码是什么才能说出解码后的字节在说什么。对于幼稚的日期时间,您必须先知道它所在的时区,然后才能说出它实际代表的时间。所以从这个意义上说,UTC 日期时间比简单的日期时间提供更多的信息。

    UTC 是协调世界时,怪怪的首字母缩写词怪法国人。时区通常被定义为与 UTC 相差整数小时,并且出于所有实际目的,您可以将 UTC 视为与 UTC 相差 0 小时的时区。它就像格林尼治标准时间,没有任何夏令时废话。

    Q5) 我如何知道何时要使用原始时间以及何时要使用 UTC 时间?

    对此存在不同意见。我的建议是始终在您的应用程序中使用 UTC 格式的所有内容(并且也只将 UTC 存储在数据库中!)。当任何日期时间数据进入您的应用程序时,无论它进入您的应用程序,请确保它已正确转换为 UTC。这也意味着您的应用程序内部的任何地方使用datetime.now()(这是一个天真的日期时间,“缺失”的tzinfo应该是机器的本地时区)而不是使用datetime.utcnow()(这是UTC 中的天真日期时间)或更好的datetime.now(tz=pytz.utc)(时区感知)。

    仅在应用的“显示”端更改为本地时区。您通常可以使用模板标签,甚至使用客户端 js 来做到这一点。

    【讨论】:

    • 完美。 +1 实用建议!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 2016-05-26
    • 1970-01-01
    相关资源
    最近更新 更多