使用本地时区在Python中获取正确的时区偏移量

时间:2013-07-18 20:21:09

标签: python timezone pytz timezone-offset

好的,首先让我说我的时区是CET / CEST。它从CEST变为CET的确切时刻(从DST返回,即GMT + 2,再到正常,GMT + 1,因此)始终是10月的最后一个星期日凌晨3点。 2010年10月31日凌晨3点。

现在请注意以下内容:

>>> 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)

如上所述,这是错误的。

>>> 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)

现在它突然变得正确:/

我知道有几个问题已经存在,但给出的解决方案始终是“使用本地化”,但我的问题是LocalTimezone不提供该方法。

事实上,我有几个时间戳,以毫秒为单位,我需要本地时区的utcoffset(不仅是我的,而是使用该程序的任何人)。其中一个是我的时区中的1288483950000或2010年10月31日02:12:30 GMT + 0200(CEST)。

目前我执行以下操作来获取datetime对象:

datetime.datetime.fromtimestamp(int(int(millis)/1E3)) 

这将在几分钟内获得utcoffset:

-int(local_tnz.utcoffset(date).total_seconds()/60)
遗憾的是,在很多场合都错了:(。

有什么想法吗?

注意:我使用的是python3.2.4,而不是在这种情况下它应该重要。

修改

感谢@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)

local_tz等于tzlocal模块中的tzlocal.get_localzone()。

3 个答案:

答案 0 :(得分:22)

根据Wikipedia,夏令时的转换发生在UTC时间01:00。

  • 在UTC时间00:12,您仍然处于中欧夏令时(即UTC + 02:00),因此当地时间是02:12。

  • 在UTC时间01:12,您回到标准中欧时间(即UTC + 01:00),所以当地时间再次是02:12。

当从夏令时变回标准时间时,当地时间从02:59回到02:00,小时重复。因此,当要求UTC偏移02:12(当地时间)时,答案可能是+01:00或+02:00 - 这取决于你所说的是哪个版本的02:12。

关于pytz库的进一步调查,我认为您的问题可能是您不应该使用pytz.reference实现,这可能无法很好地处理这些歧义。引自源代码中的注释:

  

参考Python文档中的tzinfo实现。   用于测试,因为它们只适用于多年   1987年至2006年。不要将这些用于实际代码。

使用pytz中的模糊时间

您应该做的是为适当的时区构建 timezone 对象:

import pytz
cet = pytz.timezone('CET')

然后您可以使用 utcoffset 方法计算该时区中日期/时间的UTC偏移量。

dt = datetime.datetime(2010, 10, 31, 2, 12, 30)
offset = cet.utcoffset(dt)

请注意,上面的示例将抛出 AmbiguousTimeError 异常,因为它无法分辨出你的意思是02:12:30的两个版本中的哪一个。幸运的是,pytz将允许您通过设置 is_dst 参数来指定是否需要dst版本或标准版本。例如:

offset = cet.utcoffset(dt, is_dst = True)

请注意,对所有对 utcoffset 的调用设置此参数没有坏处,即使时间不明确也是如此。根据文档,它仅在DST过渡模糊期间用于解决这种模糊性。

如何处理时间戳

至于处理时间戳,最好尽可能长时间地将它们存储为UTC值,否则你最终可能会丢掉有价值的信息。因此,首先使用 datetime.utcfromtimestamp 方法转换为UTC日期时间。

dt = datetime.datetime.utcfromtimestamp(1288483950)

然后使用pytz将时间本地化为UTC,因此时区附加到日期时间对象。

dt = pytz.utc.localize(dt)

最后,您可以将UTC日期时间转换为您当地的时区,并获取如下所示的时区偏移量:

offset = dt.astimezone(cet).utcoffset()

请注意,这组计算将为1288483950和1288487550产生正确的偏移,即使两个时间戳都在CET时区的02:12:30表示。

确定当地时区

如果您需要使用计算机的本地时区而不是固定的时区,则无法直接从pytz执行此操作。您也不能使用 time.tzname 中的时区名称构建 pytz.timezone 对象,因为pytz不会始终识别名称。

解决方案是使用tzlocal module - 它的唯一目的是在pytz中提供这个缺少的功能。你这样使用它:

import tzlocal
local_tz = tzlocal.get_localzone()

get_localzone()函数返回 pytz.timezone 对象,因此您应该能够在我使用的所有地方使用该值上面例子中的cet 变量。

答案 1 :(得分:9)

给定一个以毫秒为单位的时间戳,您只需使用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)

如果我们忽略闰秒的时间,那么就没有模糊或不存在的时间。

如果操作系统维护历史时区数据库,它支持DST和utc偏移的更改,例如,它应该在Ubuntu上用于任何过去/现在的日期,但在Windows上可能会因使用不同的utc偏移的过去日期而中断。

使用适用于* nix和Win32系统的tzlocal模块是一样的:

#!/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()

请参阅How to convert a python utc datetime to a local datetime using only python standard library?

以分钟为单位获取utc偏移量(Python 3.2 +):

from datetime import timedelta

minutes = utc_offset / timedelta(minutes=1)

请勿使用pytz.reference.LocalTimezone()it is only for tests

答案 2 :(得分:0)

  child: Text('Hello $_userName,'),

7200.0