Python datetime:tz内部方法与.replace之间的区别(tzinfo =) [英] Python datetime: difference between tz inside method and .replace(tzinfo=)

查看:81
本文介绍了Python datetime:tz内部方法与.replace之间的区别(tzinfo =)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近修复了一个错误,但仍然不知道为什么会发生。我在Django模型中将以下时间戳转换为datetimefield:

I have fixed a bug recently, but still don't know why it ocurred. I had the following convert a timestamp (epoch) to datetimefield in Django model:

our_timezone = pytz.timezone("Asia/Jerusalem")
# e13 is used for true division
final_dict["published_date"] = datetime.datetime.fromtimestamp(
            float(article_as_dict["publish_date"]) / 1e3).replace(tzinfo=our_timezone)

上面的返回了一个始终关闭39分钟的日期时间对象真实纪元时间(在我们的时区中)。

The above returned a datetime object that was always 39 minutes off the true epoch time (in our timezone).

我设法通过删除 replace 来解决此问题,而是将时区放入了 fromtimestamp 方法:

I managed to fix it by removing replace, and instead putting the timezone inside the fromtimestamp method:

final_dict["published_date"] = datetime.datetime.fromtimestamp(
            float(article_as_dict["publish_date"]) / 1e3, tz=our_timezone)

那有什么区别在 fromtimestamp 方法内指定 tz = our_timezone 和执行 .replace(tzinfo = our_timezone)创建对象之后?为什么 .replace 返回错误的时间?

So what's the difference between specifying the tz=our_timezone inside the fromtimestamp method, and doing .replace(tzinfo=our_timezone) after creating the object? why does the .replace return the wrong time?

推荐答案

>>> datetime.fromtimestamp(1000000000).replace(tzinfo=our_timezone)
datetime.datetime(2001, 9, 9, 3, 46, 40, tzinfo=<DstTzInfo 'Asia/Jerusalem' LMT+2:21:00 STD>)
>>> datetime.fromtimestamp(1000000000, tz=our_timezone)
datetime.datetime(2001, 9, 9, 4, 46, 40, tzinfo=<DstTzInfo 'Asia/Jerusalem' IDT+3:00:00 DST>)

请注意第一种情况下的奇数时区偏移。

Notice the odd timezone offset in the first case.

时区是多个偏移量的捆绑。时区偏移量随时间变化。它不仅会根据夏季和冬季的时间在一年内发生变化,而且在修订和更新时区数据时还会发生历史变化。您可以检查时区对象以获得一些有趣的历史数据,可以追溯到几十年前:

Timezones are a bundle of multiple offsets. A timezone offset changes over time. Not only does it vary within a year based on summer and winter time, it varied historically when timezone data was revised and updated. You can inspect the timezone object to get some interesting historical data, reaching back many decades:

>>> our_timezone._utc_transition_times
[datetime.datetime(1, 1, 1, 0, 0), datetime.datetime(1901, 12, 13, 20, 45, 52), datetime.datetime(1917, 12, 31, 21, 39, 20), datetime.datetime(1940, 5, 31, 22, 0), datetime.datetime(1942, 10, 31, 21, 0), datetime.datetime(1943, 4, 1, 0, 0), datetime.datetime(1943, 10, 31, 21, 0), datetime.datetime(1944, 3, 31, 22, 0), datetime.datetime(1944, 10, 31, 21, 0), datetime.datetime(1945, 4, 15, 22, 0), datetime.datetime(1945, 10, 31, 23, 0), datetime.datetime(1946, 4, 16, 0, 0), datetime.datetime(1946, 10, 31, 21, 0), datetime.datetime(1948, 5, 22, 22, 0), datetime.datetime(1948, 8, 31, 20, 0), datetime.datetime(1948, 10, 31, 23, 0), datetime.datetime(1949, 4, 30, 22, 0), datetime.datetime(1949, 10, 31, 23, 0), datetime.datetime(1950, 4, 15, 22, 0), datetime.datetime(1950, 9, 15, 0, 0), datetime.datetime(1951, 3, 31, 22, 0), datetime.datetime(1951, 11, 11, 0, 0), datetime.datetime(1952, 4, 20, 0, 0), datetime.datetime(1952, 10, 19, 0, 0), datetime.datetime(1953, 4, 12, 0, 0), datetime.datetime(1953, 9, 13, 0, 0), datetime.datetime(1954, 6, 12, 22, 0), datetime.datetime(1954, 9, 11, 21, 0), datetime.datetime(1955, 6, 11, 0, 0), datetime.datetime(1955, 9, 10, 21, 0), datetime.datetime(1956, 6, 2, 22, 0), datetime.datetime(1956, 9, 30, 0, 0), datetime.datetime(1957, 4, 29, 0, 0), datetime.datetime(1957, 9, 21, 21, 0), datetime.datetime(1974, 7, 6, 22, 0), datetime.datetime(1974, 10, 12, 21, 0), datetime.datetime(1975, 4, 19, 22, 0), datetime.datetime(1975, 8, 30, 21, 0), datetime.datetime(1985, 4, 13, 22, 0), datetime.datetime(1985, 9, 14, 21, 0), datetime.datetime(1986, 5, 17, 22, 0), datetime.datetime(1986, 9, 6, 21, 0), datetime.datetime(1987, 4, 14, 22, 0), datetime.datetime(1987, 9, 12, 21, 0), datetime.datetime(1988, 4, 9, 22, 0), datetime.datetime(1988, 9, 3, 21, 0), datetime.datetime(1989, 4, 29, 22, 0), datetime.datetime(1989, 9, 2, 21, 0), datetime.datetime(1990, 3, 24, 22, 0), datetime.datetime(1990, 8, 25, 21, 0), datetime.datetime(1991, 3, 23, 22, 0), datetime.datetime(1991, 8, 31, 21, 0), datetime.datetime(1992, 3, 28, 22, 0), datetime.datetime(1992, 9, 5, 21, 0), datetime.datetime(1993, 4, 1, 22, 0), datetime.datetime(1993, 9, 4, 21, 0), datetime.datetime(1994, 3, 31, 22, 0), datetime.datetime(1994, 8, 27, 21, 0), datetime.datetime(1995, 3, 30, 22, 0), datetime.datetime(1995, 9, 2, 21, 0), datetime.datetime(1996, 3, 14, 22, 0), datetime.datetime(1996, 9, 15, 21, 0), datetime.datetime(1997, 3, 20, 22, 0), datetime.datetime(1997, 9, 13, 21, 0), datetime.datetime(1998, 3, 19, 22, 0), datetime.datetime(1998, 9, 5, 21, 0), datetime.datetime(1999, 4, 2, 0, 0), datetime.datetime(1999, 9, 2, 23, 0), datetime.datetime(2000, 4, 14, 0, 0), datetime.datetime(2000, 10, 5, 22, 0), datetime.datetime(2001, 4, 8, 23, 0), datetime.datetime(2001, 9, 23, 22, 0), datetime.datetime(2002, 3, 28, 23, 0), datetime.datetime(2002, 10, 6, 22, 0), datetime.datetime(2003, 3, 27, 23, 0), datetime.datetime(2003, 10, 2, 22, 0), datetime.datetime(2004, 4, 6, 23, 0), datetime.datetime(2004, 9, 21, 22, 0), datetime.datetime(2005, 4, 1, 0, 0), datetime.datetime(2005, 10, 8, 23, 0), datetime.datetime(2006, 3, 31, 0, 0), datetime.datetime(2006, 9, 30, 23, 0), datetime.datetime(2007, 3, 30, 0, 0), datetime.datetime(2007, 9, 15, 23, 0), datetime.datetime(2008, 3, 28, 0, 0), datetime.datetime(2008, 10, 4, 23, 0), datetime.datetime(2009, 3, 27, 0, 0), datetime.datetime(2009, 9, 26, 23, 0), datetime.datetime(2010, 3, 26, 0, 0), datetime.datetime(2010, 9, 11, 23, 0), datetime.datetime(2011, 4, 1, 0, 0), datetime.datetime(2011, 10, 1, 23, 0), datetime.datetime(2012, 3, 30, 0, 0), datetime.datetime(2012, 9, 22, 23, 0), datetime.datetime(2013, 3, 29, 0, 0), datetime.datetime(2013, 10, 26, 23, 0), datetime.datetime(2014, 3, 28, 0, 0), datetime.datetime(2014, 10, 25, 23, 0), datetime.datetime(2015, 3, 27, 0, 0), datetime.datetime(2015, 10, 24, 23, 0), datetime.datetime(2016, 3, 25, 0, 0), datetime.datetime(2016, 10, 29, 23, 0), datetime.datetime(2017, 3, 24, 0, 0), datetime.datetime(2017, 10, 28, 23, 0), datetime.datetime(2018, 3, 23, 0, 0), datetime.datetime(2018, 10, 27, 23, 0), datetime.datetime(2019, 3, 29, 0, 0), datetime.datetime(2019, 10, 26, 23, 0), datetime.datetime(2020, 3, 27, 0, 0), datetime.datetime(2020, 10, 24, 23, 0), datetime.datetime(2021, 3, 26, 0, 0), datetime.datetime(2021, 10, 30, 23, 0), datetime.datetime(2022, 3, 25, 0, 0), datetime.datetime(2022, 10, 29, 23, 0), datetime.datetime(2023, 3, 24, 0, 0), datetime.datetime(2023, 10, 28, 23, 0), datetime.datetime(2024, 3, 29, 0, 0), datetime.datetime(2024, 10, 26, 23, 0), datetime.datetime(2025, 3, 28, 0, 0), datetime.datetime(2025, 10, 25, 23, 0), datetime.datetime(2026, 3, 27, 0, 0), datetime.datetime(2026, 10, 24, 23, 0), datetime.datetime(2027, 3, 26, 0, 0), datetime.datetime(2027, 10, 30, 23, 0), datetime.datetime(2028, 3, 24, 0, 0), datetime.datetime(2028, 10, 28, 23, 0), datetime.datetime(2029, 3, 23, 0, 0), datetime.datetime(2029, 10, 27, 23, 0), datetime.datetime(2030, 3, 29, 0, 0), datetime.datetime(2030, 10, 26, 23, 0), datetime.datetime(2031, 3, 28, 0, 0), datetime.datetime(2031, 10, 25, 23, 0), datetime.datetime(2032, 3, 26, 0, 0), datetime.datetime(2032, 10, 30, 23, 0), datetime.datetime(2033, 3, 25, 0, 0), datetime.datetime(2033, 10, 29, 23, 0), datetime.datetime(2034, 3, 24, 0, 0), datetime.datetime(2034, 10, 28, 23, 0), datetime.datetime(2035, 3, 23, 0, 0), datetime.datetime(2035, 10, 27, 23, 0), datetime.datetime(2036, 3, 28, 0, 0), datetime.datetime(2036, 10, 25, 23, 0), datetime.datetime(2037, 3, 27, 0, 0), datetime.datetime(2037, 10, 24, 23, 0)]

使用 datetime.fromtimestamp(1000000000)可以创建朴素时间戳,没有时区信息。然后,您只需使用 replace 将时区对象附加到该对象即可。这只会导致Python使用该时区对象中的许多偏移量对象中的第一个,从而导致距100年前的偏移量很奇怪。

With datetime.fromtimestamp(1000000000) you create a naïve timestamp, one without timezone information. You then simply attach the timezone object to it with replace. That just causes Python to use the first of the many offset objects in that timezone object, which results in an odd offset from a hundred years ago.

但是,提供时区对象作为上下文信息直接从timestamp 发送到,该方法可以选择适用于时间戳的正确偏移量并正确生成一个连贯的时间戳对象。

However, supplying the timezone object as "context information" to fromtimestamp directly, that method can pick the correct offset applicable to the timestamp and correctly produces a coherent timestamp object.

您也可以在事实发生后使用 astimezone

You could also do this after the fact with astimezone:

>>> datetime.fromtimestamp(1000000000).astimezone(our_timezone)
datetime.datetime(2001, 9, 9, 4, 46, 40, tzinfo=<DstTzInfo 'Asia/Jerusalem' IDT+3:00:00 DST>)

此方法还可以智能地选择适用的偏移量。

This method also intelligently picks the applicable offset.

简而言之:替换 ==哑,只需覆盖原始数据, fromtimestamp astimezone ==聪明,知道如何使用时区。

In a nutshell: replace == dumb, simply overwrite raw data, fromtimestamp, astimezone == smart, knows how to work with timezones.

这篇关于Python datetime:tz内部方法与.replace之间的区别(tzinfo =)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆