好的,让我先说我的时区是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)
现在它突然正确了:/
我知道已经有几个关于这个问题的问题,但给出的解决方案始终是"使用本地化",但我的问题是本地时区不提供该方法。
事实上,我有几个以毫秒为单位的时间戳,我需要本地时区的 utcoffed(不仅是我的,还有使用该程序的任何人(。其中之一是1288483950000或 Sun Oct 31 2010 02:12:30 GMT+0200 (CEST( 在我的时区。
目前,我执行以下操作来获取日期时间对象:
datetime.datetime.fromtimestamp(int(int(millis)/1E3))
这要在几分钟内获得 UTC偏移量:
-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((。
根据维基百科,往返夏令时的过渡发生在 01:00 UTC。
-
在 00:12 UTC,您仍在中欧夏令时(即 UTC+02:00(,因此当地时间是 02:12。
在 01: 12 UTC,您将回到标准的中欧时间(即 UTC+01:00(,因此当地时间再次为 02:12。
当从夏令时更改回标准时间时,本地时间从 02:59 回到 02:00,并且小时会重复。因此,当询问 02:12(当地时间(的 UTC 偏移量时,答案可能是 +01:00 或 +02:00 - 这取决于您谈论的是哪个版本的 02:12。
在对pytz库的进一步调查中,我认为您的问题可能是您不应该使用pytz.reference实现,它可能无法很好地处理这些歧义。引用源代码中的注释:
引用 Python 文档中的 tzinfo 实现。 用于测试,因为它们仅在年份内正确 1987年至2006年。不要将这些用于实际代码。
在 pytz 中使用模棱两可的时间
您应该做的是为适当的时区构造一个时区对象:
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 模块 - 它的唯一目的是在 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)
如果我们忽略闰秒前后的时间,那么就没有歧义或不存在的时间。
如果操作系统维护历史时区数据库,它支持夏令时和出于其他原因更改 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()
请参阅如何仅使用 python 标准库将 python utc 日期时间转换为本地日期时间?
要以分钟为单位获取 utc 偏移量(Python 3.2+(:
from datetime import timedelta
minutes = utc_offset / timedelta(minutes=1)
不要使用pytz.reference.LocalTimezone()
,它仅用于测试。
import pytz, datetime
tz = timezone('CET')
tz.utcoffset(datetime.datetime.now()).total_seconds()
7200,0
> other_datetime = "YYYY-mm-ddTHH:MM:SSother_offset"
可以是空格或字符"T"本身。
other_offset通常表示为"+HHMM"或"-HHMM">
然后你只需这样做:
- 得到我自己的
timezone offset := my_offset
-
my_datetime = other_datetime + minutes( my_offset - other_offset)
Rembember my_offset和other_offset可以是正数,也可以是负数。
因此,您最终可能会执行以下操作:
my_datetime = other_datetime + minutes( (-7:00) - (-8:00) ) = other_datetime + minutes(+1:00) = other_datetime + 60 minutes
等
请注意双重否定。