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

Jor*_*ren 18 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)
Run Code Online (Sandbox Code Playgroud)

如上所述,这是错误的.

>>> 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)
Run Code Online (Sandbox Code Playgroud)

现在它突然变得正确:/

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

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

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

datetime.datetime.fromtimestamp(int(int(millis)/1E3)) 
Run Code Online (Sandbox Code Playgroud)

这将在几分钟内得到utcoffset:

-int(local_tnz.utcoffset(date).total_seconds()/60)
Run Code Online (Sandbox Code Playgroud)

不幸的是,在很多场合都是错的:(.

有任何想法吗?

注意:我正在使用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)
Run Code Online (Sandbox Code Playgroud)

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

Jam*_*ess 27

根据维基百科,夏季时间的转换发生在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中处理模棱两可的时间

你应该做的是为适当的时区构建一个时区对象:

import pytz
cet = pytz.timezone('CET')
Run Code Online (Sandbox Code Playgroud)

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

dt = datetime.datetime(2010, 10, 31, 2, 12, 30)
offset = cet.utcoffset(dt)
Run Code Online (Sandbox Code Playgroud)

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

offset = cet.utcoffset(dt, is_dst = True)
Run Code Online (Sandbox Code Playgroud)

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

如何处理时间戳

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

dt = datetime.datetime.utcfromtimestamp(1288483950)
Run Code Online (Sandbox Code Playgroud)

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

dt = pytz.utc.localize(dt)
Run Code Online (Sandbox Code Playgroud)

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

offset = dt.astimezone(cet).utcoffset()
Run Code Online (Sandbox Code Playgroud)

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

确定当地时区

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

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

import tzlocal
local_tz = tzlocal.get_localzone()
Run Code Online (Sandbox Code Playgroud)

get_localzone()函数返回一个pytz.timezone对象,所以你应该能够使用该值在我使用的所有地方CET变量在上面的例子.


jfs*_*jfs 10

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

如果我们忽略闰秒的时间,则没有模糊或不存在的时间.

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

这里使用的tzlocal模块应该适用于*nix和Win32系统:

#!/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()
Run Code Online (Sandbox Code Playgroud)

请参阅如何仅使用python标准库将python utc datetime转换为本地日期时间?

要在几分钟内获得utc偏移量(Python 3.2+):

from datetime import timedelta

minutes = utc_offset / timedelta(minutes=1)
Run Code Online (Sandbox Code Playgroud)

不要使用pytz.reference.LocalTimezone(),它仅用于测试.