使用本地时区在 Python 中获取正确的时区偏移量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17733139/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting the correct timezone offset in Python using local timezone
提问by Joren Van Severen
Ok let me first start by saying my timezone is CET/CEST. The exact moment it changes from CEST to CET (back from DST, which is GMT+2, to normal, which GMT+1, thus) is always the last Sunday of October at 3AM. In 2010 this was 31 October 3AM.
好的,让我首先说我的时区是 CET/CEST。它从 CEST 更改为 CET(从 DST 返回,即 GMT+2,变为正常,即 GMT+1,因此)的确切时刻始终是 10 月的最后一个星期日凌晨 3 点。在 2010 年,这是 10 月 31 日凌晨 3 点。
Now note the following:
现在注意以下几点:
>>> import datetime
>>> import pytz.reference
>>> local_tnz = pytz.reference.LocalTimezone()
>>> local_tnz.utcoffset(datetime.datetime(2010, 10, 31, 2, 12, 30))
datetime.timedelta(0, 3600)
This is wrong as explained above.
如上所述,这是错误的。
>>> local_tnz.utcoffset(datetime.datetime(2010, 10, 30, 2, 12, 30))
datetime.timedelta(0, 7200)
>>> local_tnz.utcoffset(datetime.datetime(2010, 10, 31, 2, 12, 30))
datetime.timedelta(0, 7200)
Now it is suddenly correct :/
现在突然正确了:/
I know there are several questions about this already, but the solution given is always "use localize", but my problem here is that the LocalTimezone does not provide that method.
我知道已经有几个关于此的问题,但给出的解决方案始终是“使用本地化”,但我的问题是 LocalTimezone 不提供该方法。
In fact, I have several timestamps in milliseconds of which I need the utcoffset of the local timezone (not just mine, but of anyone using the program). One of these is 1288483950000 or Sun Oct 31 2010 02:12:30 GMT+0200 (CEST) in my timezone.
事实上,我有几个以毫秒为单位的时间戳,其中我需要本地时区的 utcoffset(不仅是我的,还有使用该程序的任何人)。其中之一是 1288483950000 或 Sun Oct 31 2010 02:12:30 GMT+0200 (CEST) 在我的时区。
Currently I do the following to get the datetime object:
目前我执行以下操作来获取日期时间对象:
datetime.datetime.fromtimestamp(int(int(millis)/1E3))
and this to get the utcoffset in minutes:
这是在几分钟内获得 utcoffset 的:
-int(local_tnz.utcoffset(date).total_seconds()/60)
which, unfortunately, is wrong in many occasions :(.
不幸的是,这在很多情况下都是错误的:(。
Any ideas?
有任何想法吗?
Note: I'm using python3.2.4, not that it should matter in this case.
注意:我使用的是 python3.2.4,在这种情况下并不重要。
EDIT:
编辑:
Found the solution thanks to @JamesHolderness:
感谢@JamesHolderness 找到了解决方案:
def datetimeFromMillis(millis):
return pytz.utc.localize(datetime.datetime.utcfromtimestamp(int(int(millis)/1E3)))
def getTimezoneOffset(date):
return -int(date.astimezone(local_tz).utcoffset().total_seconds()/60)
With local_tz equal to tzlocal.get_localzone() from the tzlocal module.
local_tz 等于 tzlocal 模块中的 tzlocal.get_localzone() 。
采纳答案by James Holderness
According to Wikipedia, the transition to and from Summer Time occurs at 01:00 UTC.
根据维基百科,与夏令时的转换发生在 UTC 时间 01:00。
At 00:12 UTC you are still in Central European Summer Time (i.e. UTC+02:00), so the local time is 02:12.
At 01:12 UTC you are back in the standard Central European Time (i.e. UTC+01:00), so the local time is again 02:12.
在 00:12 UTC,您仍处于中欧夏令时(即 UTC+02:00),因此当地时间为 02:12。
在 UTC 时间 01:12,您返回到标准的中欧时间(即 UTC+01:00),因此当地时间又是 02:12。
When changing from Summer Time back to standard time, the local time goes from 02:59 back to 02:00 and the hour repeats itself. So when asking for the UTC offset of 02:12 (local time), the answer could truthfully be either +01:00 or +02:00 - it depends which version of 02:12 you are talking about.
当从夏令时改回标准时间时,当地时间从 02:59 返回到 02:00,并且小时重复。因此,当询问 02:12(当地时间)的 UTC 偏移量时,答案可能是 +01:00 或 +02:00 - 这取决于您所谈论的 02:12 的哪个版本。
On further investigation of the pytz library, I think your problem may be that you shouldn't be using the pytz.reference implementation, which may not deal with these ambiguities very well. Quoting from the comments in the source code:
在进一步调查 pytz 库时,我认为您的问题可能是您不应该使用 pytz.reference 实现,这可能无法很好地处理这些歧义。引用源代码中的注释:
Reference tzinfo implementations from the Python docs. Used for testing against as they are only correct for the years 1987 to 2006. Do not use these for real code.
从 Python 文档中参考 tzinfo 实现。用于测试,因为它们仅适用于 1987 年到 2006 年。请勿将这些用于实际代码。
Working with ambiguous times in pytz
在 pytz 中处理模棱两可的时间
What you should be doing is constructing a timezoneobject for the appropriate timezone:
您应该做的是为适当的时区构建一个时区对象:
import pytz
cet = pytz.timezone('CET')
Then you can use the utcoffsetmethod to calculate the UTC offset of a date/time in that timezone.
然后您可以使用utcoffset方法计算该时区中日期/时间的 UTC 偏移量。
dt = datetime.datetime(2010, 10, 31, 2, 12, 30)
offset = cet.utcoffset(dt)
Note, that the above example will throw an AmbiguousTimeErrorexception, because it can't tell which of the two versions of 02:12:30 you meant. Fortunately pytz will let you specify whether you want the dst version or the standard version by setting the is_dstparameter. For example:
请注意,上面的示例将抛出AmbiguousTimeError异常,因为它无法判断您指的是 02:12:30 的两个版本中的哪一个。幸运的是 pytz 会让你通过设置is_dst参数来指定你想要 dst 版本还是标准版本。例如:
offset = cet.utcoffset(dt, is_dst = True)
Note that it doesn't harm to set this parameter on all calls to utcoffset, even if the time wouldn't be ambiguous. According to the documentation, it is only used during DST transition ambiguous periods to resolve that ambiguity.
请注意,在对utcoffset 的所有调用中设置此参数并没有什么坏处,即使时间不会模糊。根据文档,它仅在 DST 过渡模糊时期使用来解决该模糊性。
How to deal with timestamps
如何处理时间戳
As for dealing with timestamps, it's best you store them as UTC values for as long as possible, otherwise you potentially end up throwing away valuable information. So first convert to a UTC datetime with the datetime.utcfromtimestampmethod.
至于处理时间戳,最好将它们作为 UTC 值存储尽可能长的时间,否则最终可能会丢弃有价值的信息。因此,首先使用datetime.utcfromtimestamp方法转换为 UTC 日期时间。
dt = datetime.datetime.utcfromtimestamp(1288483950)
Then use pytz to localize the time as UTC, so the timezone is attached to the datetime object.
然后使用 pytz 将时间本地化为 UTC,因此时区附加到 datetime 对象。
dt = pytz.utc.localize(dt)
Finally you can convert that UTC datetime into your local timezone, and obtain the timezone offset like this:
最后,您可以将该 UTC 日期时间转换为您的本地时区,并像这样获取时区偏移量:
offset = dt.astimezone(cet).utcoffset()
Note that this set of calculations will produce the correct offsets for both 1288483950 and 1288487550, even though both timestamps are represented by 02:12:30 in the CET timezone.
请注意,这组计算将为 1288483950 和 1288487550 生成正确的偏移量,即使两个时间戳都由 CET 时区中的 02:12:30 表示。
Determining the local timezone
确定本地时区
If you need to use the local timezone of your computer rather than a fixed timezone, you can't do that from pytz directly. You also can't just construct a pytz.timezoneobject using the timezone name from time.tzname, because the names won't always be recognised by pytz.
如果您需要使用计算机的本地时区而不是固定时区,则不能直接从 pytz 执行此操作。您也不能仅使用time.tzname中的时区名称构造pytz.timezone对象,因为pytz并不总是能够识别这些名称。
The solution is to use the tzlocal module- its sole purpose is to provide this missing functionality in pytz. You use it like this:
解决方案是使用tzlocal 模块——它的唯一目的是在 pytz 中提供这个缺失的功能。你像这样使用它:
import tzlocal
local_tz = tzlocal.get_localzone()
The get_localzone()function returns a pytz.timezoneobject, so you should be able to use that value in all the places I've used the cetvariable in the examples above.
该get_localzone()函数返回一个pytz.timezone对象,所以你应该能够使用该值在所有我用的地方CET变量在上面的例子。
回答by jfs
Given a timestamp in milliseconds you can get the utc offset for the local timezone using only stdlib:
给定以毫秒为单位的时间戳,您可以仅使用 stdlib 获取本地时区的 utc 偏移量:
#!/usr/bin/env python
from datetime import datetime
millis = 1288483950000
ts = millis * 1e-3
# local time == (utc time + utc offset)
utc_offset = datetime.fromtimestamp(ts) - datetime.utcfromtimestamp(ts)
If we ignore time around leap seconds then there is no ambiguity or non-existent times.
如果我们忽略闰秒左右的时间,那么就没有歧义或不存在的时间。
It supports DST and changes of the utc offset for other reasons if OS maintains a historical timezone db e.g., it should work on Ubuntu for any past/present date but might break on Windows for past dates that used different utc offset.
如果操作系统维护历史时区数据库,它支持 DST 和其他原因的 utc 偏移更改,例如,它应该在 Ubuntu 上工作任何过去/现在日期,但可能会在 Windows 上中断使用不同 utc 偏移的过去日期。
Here's the same using tzlocal
module that should work on *nix and Win32 systems:
这tzlocal
是应该在 *nix 和 Win32 系统上工作的相同 using模块:
#!/usr/bin/env python
from datetime import datetime
from tzlocal import get_localzone # pip install tzlocal
millis = 1288483950000
ts = millis * 1e-3
local_dt = datetime.fromtimestamp(ts, get_localzone())
utc_offset = local_dt.utcoffset()
See How to convert a python utc datetime to a local datetime using only python standard library?
请参阅如何仅使用 python 标准库将 python utc 日期时间转换为本地日期时间?
To get the utc offset in minutes (Python 3.2+):
要以分钟为单位获取 utc 偏移量(Python 3.2+):
from datetime import timedelta
minutes = utc_offset / timedelta(minutes=1)
Don't use pytz.reference.LocalTimezone()
, it is only for tests.
不要使用pytz.reference.LocalTimezone()
,它仅用于测试。