Django/python - 消除关于日期和时区意识的困惑
Django/python - dispelling confusion regarding dates and timezone-awareness
我一直在广泛处理 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
函数告诉我什么?是说 "a man standing in eastern Canada looking at his calendar sees "2015-12-02"?还是说 "This is "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_django
和 now_aware_with_datetime
的行为似乎相似,但它们的控制台输出表明它们不同。
Q2) now_aware_with_django
和now_aware_with_datetime
有什么区别?
Q3) 我怎么知道我是否需要使用 timezone.make_aware
或 datetime.replace
?
原始日期时间与 UTC 日期时间
UTC
表示时间值没有变化。 "Naive" 似乎意味着时间没有与之关联的时区。
Q4) naive 和 UTC 日期时间有什么区别?看起来它们完全相同 - 都没有对实际时间值进行任何转换。
Q5) 我怎么知道什么时候要使用 naive 时间,什么时候要使用 UTC 时间?
如果我能得到所有 5 个问题的答案,那将是非常好的。非常感谢!
Q1) 这个日期时间对象说是 2015-12-02 - generate_a_datetime 函数告诉我什么?它是说 "a man standing in eastern Canada looking at his calendar sees "2015-12-02"?还是说 "This is "2015-12-02 UTC"...但不要忘记将其调整为加拿大东部时区! "
第一种解释是正确的。时区感知日期时间已经为您 "adjusted",而 tzinfo 只是告诉您它在哪个时区中指定。
Q2) now_aware_with_django
和now_aware_with_datetime
有什么区别?
对于第一种情况,您正在创建一个日期时间,它表示与 'naive' 相同的时间点,那是 假设 天真的那个在您当地时区。
对于第二种情况,您说的是天真的那个已经在您提供的时区内,然后您只需添加 tzinfo。
Q3) 我如何知道我是否需要使用 timezone.make_aware
或 datetime.replace?
好吧,由于它们做不同的事情,您需要知道您要做什么才能知道使用哪个。如果你想从一个天真的时区(在你的本地时间)转换成一个不同的时区,你可以使用 make_aware
。如果你已经知道你天真的日期时间的时区,你只需使用替换(或查看pytz
中的localize
,对此要更加小心任务)。
注意: 通常,如果您一开始就有任何天真的日期时间,那么您之前做错了什么,您应该及早发现。尝试让他们了解您应用程序的边界——我将在第 5 季度详细介绍这一点。
Q4) naive 和 UTC 日期时间有什么区别?看起来它们完全相同 - 都没有对实际时间值进行任何转换。
天真的日期时间只是一个日期时间,它不会告诉您它所在的时区。它不一定是 UTC,它可以是任何东西。它类似于 bytestrings 和 unicode - 你必须知道编码是什么才能说出解码后的字节在说什么。对于天真的日期时间,您必须先知道它所在的时区,然后才能说出它实际代表的时间。因此,从这个意义上说,UTC 日期时间提供了比原始日期时间更多的信息。
UTC 是协调世界时,怪怪的缩写怪法国人。时区通常定义为与 UTC 相差整数小时,出于所有实际目的,您可以将 UTC 视为与 UTC 相差 0 小时的时区。它就像没有任何夏令时废话的格林威治标准时间。
Q5) 我怎么知道什么时候要使用 naive 时间,什么时候要使用 UTC 时间?
对此众说纷纭。我的建议是始终在您的应用程序中使用 UTC 中的所有内容(并且也只将 UTC 存储在数据库中!)。当任何日期时间数据进入您的应用程序时,无论它以何种方式进入您的应用程序,请确保它已正确转换为 UTC。这也意味着任何地方 inside 你的应用程序使用 datetime.now()
(这是一个天真的日期时间与 "missing" tzinfo 应该是机器的本地时区)使用 datetime.utcnow()
(UTC 中的原始日期时间)或更好的 datetime.now(tz=pytz.utc)
(时区感知)。
仅在应用程序的 "display" 端更改为本地时区。您通常可以使用模板标签甚至客户端 js 来执行此操作。
我一直在广泛处理 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
函数告诉我什么?是说 "a man standing in eastern Canada looking at his calendar sees "2015-12-02"?还是说 "This is "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_django
和 now_aware_with_datetime
的行为似乎相似,但它们的控制台输出表明它们不同。
Q2) now_aware_with_django
和now_aware_with_datetime
有什么区别?
Q3) 我怎么知道我是否需要使用 timezone.make_aware
或 datetime.replace
?
原始日期时间与 UTC 日期时间
UTC
表示时间值没有变化。 "Naive" 似乎意味着时间没有与之关联的时区。
Q4) naive 和 UTC 日期时间有什么区别?看起来它们完全相同 - 都没有对实际时间值进行任何转换。
Q5) 我怎么知道什么时候要使用 naive 时间,什么时候要使用 UTC 时间?
如果我能得到所有 5 个问题的答案,那将是非常好的。非常感谢!
Q1) 这个日期时间对象说是 2015-12-02 - generate_a_datetime 函数告诉我什么?它是说 "a man standing in eastern Canada looking at his calendar sees "2015-12-02"?还是说 "This is "2015-12-02 UTC"...但不要忘记将其调整为加拿大东部时区! "
第一种解释是正确的。时区感知日期时间已经为您 "adjusted",而 tzinfo 只是告诉您它在哪个时区中指定。
Q2) now_aware_with_django
和now_aware_with_datetime
有什么区别?
对于第一种情况,您正在创建一个日期时间,它表示与 'naive' 相同的时间点,那是 假设 天真的那个在您当地时区。
对于第二种情况,您说的是天真的那个已经在您提供的时区内,然后您只需添加 tzinfo。
Q3) 我如何知道我是否需要使用 timezone.make_aware
或 datetime.replace?
好吧,由于它们做不同的事情,您需要知道您要做什么才能知道使用哪个。如果你想从一个天真的时区(在你的本地时间)转换成一个不同的时区,你可以使用 make_aware
。如果你已经知道你天真的日期时间的时区,你只需使用替换(或查看pytz
中的localize
,对此要更加小心任务)。
注意: 通常,如果您一开始就有任何天真的日期时间,那么您之前做错了什么,您应该及早发现。尝试让他们了解您应用程序的边界——我将在第 5 季度详细介绍这一点。
Q4) naive 和 UTC 日期时间有什么区别?看起来它们完全相同 - 都没有对实际时间值进行任何转换。
天真的日期时间只是一个日期时间,它不会告诉您它所在的时区。它不一定是 UTC,它可以是任何东西。它类似于 bytestrings 和 unicode - 你必须知道编码是什么才能说出解码后的字节在说什么。对于天真的日期时间,您必须先知道它所在的时区,然后才能说出它实际代表的时间。因此,从这个意义上说,UTC 日期时间提供了比原始日期时间更多的信息。
UTC 是协调世界时,怪怪的缩写怪法国人。时区通常定义为与 UTC 相差整数小时,出于所有实际目的,您可以将 UTC 视为与 UTC 相差 0 小时的时区。它就像没有任何夏令时废话的格林威治标准时间。
Q5) 我怎么知道什么时候要使用 naive 时间,什么时候要使用 UTC 时间?
对此众说纷纭。我的建议是始终在您的应用程序中使用 UTC 中的所有内容(并且也只将 UTC 存储在数据库中!)。当任何日期时间数据进入您的应用程序时,无论它以何种方式进入您的应用程序,请确保它已正确转换为 UTC。这也意味着任何地方 inside 你的应用程序使用 datetime.now()
(这是一个天真的日期时间与 "missing" tzinfo 应该是机器的本地时区)使用 datetime.utcnow()
(UTC 中的原始日期时间)或更好的 datetime.now(tz=pytz.utc)
(时区感知)。
仅在应用程序的 "display" 端更改为本地时区。您通常可以使用模板标签甚至客户端 js 来执行此操作。