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

2024-06-16 14:41:42 发布

您现在位置:Python中文网/ 问答频道 /正文

好的,我先说我的时区是CET/CEST。从CEST到CET(从DST(即GMT+2)到normal(即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模块中获取_localzone()。


Tags: importdatetimedatelocal时间timedeltaintreference
2条回答

根据Wikipedia,夏令时和夏令时的转换发生在协调世界时01:00。

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

  • 在UTC时间01:12,您又回到了标准中欧时间(即UTC+01:00),因此本地时间又是02:12。

当从夏季时间改回标准时间时,当地时间从02:59变回02:00,并且时间会重复。因此,当要求02:12(当地时间)的UTC偏移量时,答案可能是+01:00或+02:00—这取决于您所说的02:12的版本。

在进一步研究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.

在pytz中处理不明确的时间

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

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

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

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

注意,上面的示例将抛出一个模糊的ustimeerror异常,因为它无法区分您指的是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,以便将时区附加到datetime对象。

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变量的所有地方使用该值。

给定时间戳(以毫秒为单位),您可以仅使用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)

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

如果OS维护一个历史时区db,它支持DST和更改utc偏移量,例如,对于任何过去/现在的日期,它都应该在Ubuntu上工作,但是对于使用不同utc偏移量的过去日期,它可能会在Windows上中断。

使用^{}模块在*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()

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

相关问题 更多 >