如何在Python中比较两个时区?

10 投票
4 回答
2448 浏览
提问于 2025-04-18 10:05

示例

 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 个回答

0

根据@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,时区可能不会对齐。

1

如果你不想进行转换的唯一原因是觉得效率低,我就会怀疑这真的有必要。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
8

它们并不代表同样的东西。

  • "CET" 始终是 UTC+01:00。

  • "Europe/Berlin" 在冬天是 CET (UTC+01:00),而在夏天是 CEST (UTC+02:00)。

另外,看看:

关于编辑,Europe/Rome 是一个独特的时区。它和 Europe/BerlinEurope/Zurich、以及 Europe/Amsterdam 都不一样,至少在它们的整个历史上都是如此。

如果你比较它们的定义(使用上面段落中的链接),你会发现它们在过去的某个时间点都遵循了“欧盟”关于 CET/CEST 的规则。罗马和柏林自1980年起,苏黎世自1981年起,阿姆斯特丹自1977年起。在这些日期之前,它们的规则差异很大。其他时区也有不同的规则。

如果你对这些时区的历史感兴趣,我建议你查看一下 TZ 数据中的 europe 文件。里面的评论非常有趣。

另一方面,如果你只处理现代日期,而所有时区都遵循相同的规则和偏移量,那么你可以认为这些是可以互换的——至少在未来不发生变化的情况下。

另外,确实有一些时区只是别名,完全可以互换。在 TZ 数据中,它们被称为“链接”。例如,你可以在 这里 看到 Europe/VaticanEurope/San_Marino 都链接到 Europe/Rome,因此它们是等价的。

7

这有点简单粗糙,但我可以把两个时区的时间差和一个特定的时间戳进行比较。

from datetime import datetime
today = datetime.today()
b.utcoffset(today) == c.utcoffset(today)

撰写回答