如何在Python中比较两个时区?
示例
import pytz
b=pytz.timezone('Europe/Rome')
c=pytz.timezone('Europe/Berlin')
这两个时区名字不同,但实际上代表的是同一个东西。不过
- b==c 返回的是 false
- b.zone 和 c.zone 是不同的
有没有办法能看出 b 实际上等于 c 呢?
具体的问题是,我需要转换一个 pandas 数据框的时区,但只有在这个时区和 c 不同的时候才转换。原来的时区可能是 b,在这种情况下我不想转换,因为把 b 转换成 c 是浪费时间(因为它们最终代表的是同一个时区……)
谢谢大家的帮助。
更新: 把 'CET' 改成 'Europe/Rome',以确保示例中的时区是相同的,这是根据一个回答的反馈做的修改。
4 个回答
根据@chrisaycock的回答,这里有一个Python函数,可以检查两个时区的UTC偏移量和夏令时转换是否相同:
import pytz
from datetime import datetime
def is_same_timezone(a: Union[pytz.timezone, str, bytes], b: Union[pytz.timezone, str, bytes], relative_to: datetime = None) -> bool:
"""
Return True if the timezones result in the same utc offset near the relative_to datetime, otherwise False.
Makes sure UTC offset is the same, at time of `relative_to`.
Makes sure DST transitions are the same, for the year of `relative_to`.
Defaults to checking relative to the current year.
"""
if a is None or b is None:
return False
if isinstance(a, bytes):
a = a.decode()
if isinstance(b, bytes):
b = b.decode()
if isinstance(a, str):
a = pytz.timezone(a)
if isinstance(b, str):
b = pytz.timezone(b)
relative_to = relative_to or datetime.utcnow()
if a.utcoffset(relative_to) != b.utcoffset(relative_to):
return False
year = relative_to.year
dsta = list(filter(lambda dt: dt.year == year, a._utc_transition_times))
dstb = list(filter(lambda dt: dt.year == year, b._utc_transition_times))
return dsta == dstb
我用这个函数只是为了显示,目的是在用户查看不同时间区的仪表盘时,给他们一个指示。如果仪表盘的时间区范围匹配,我就不想显示这个指示。不过,我还是会保存原始的Olson时区,因为这代表了用户的偏好。而且,时区是会变化的,所以相对于不同的datetime
,时区可能不会对齐。
如果你不想进行转换的唯一原因是觉得效率低,我就会怀疑这真的有必要。Wes McKinney写了一篇很不错的博客,讲的是向量化的日期时间转换,地址在这里:http://wesmckinney.com/blog/?p=506。举个例子,假设有一个包含100万行的数据系列。
In [1]: from pandas import *
In [2]: import numpy as np
In [3]: rng = date_range('3/6/2012', periods=1000000, freq='s', tz='US/Eastern')
In [4]: ts = Series(np.random.randn(len(rng)),rng)
In [5]: %timeit ts.tz_convert('utc')
100 loops, best of 3: 2.17 ms per loop
它们并不代表同样的东西。
"CET"
始终是 UTC+01:00。"Europe/Berlin"
在冬天是 CET (UTC+01:00),而在夏天是 CEST (UTC+02:00)。
另外,看看:
关于编辑,Europe/Rome
是一个独特的时区。它和 Europe/Berlin
、Europe/Zurich
、以及 Europe/Amsterdam
都不一样,至少在它们的整个历史上都是如此。
如果你比较它们的定义(使用上面段落中的链接),你会发现它们在过去的某个时间点都遵循了“欧盟”关于 CET/CEST 的规则。罗马和柏林自1980年起,苏黎世自1981年起,阿姆斯特丹自1977年起。在这些日期之前,它们的规则差异很大。其他时区也有不同的规则。
如果你对这些时区的历史感兴趣,我建议你查看一下 TZ 数据中的 europe 文件。里面的评论非常有趣。
另一方面,如果你只处理现代日期,而所有时区都遵循相同的规则和偏移量,那么你可以认为这些是可以互换的——至少在未来不发生变化的情况下。
另外,确实有一些时区只是别名,完全可以互换。在 TZ 数据中,它们被称为“链接”。例如,你可以在 这里 看到 Europe/Vatican
和 Europe/San_Marino
都链接到 Europe/Rome
,因此它们是等价的。
这有点简单粗糙,但我可以把两个时区的时间差和一个特定的时间戳进行比较。
from datetime import datetime
today = datetime.today()
b.utcoffset(today) == c.utcoffset(today)