Python:如何将日期时间/时间戳从一个时区转换为另一个时区?

Posted

技术标签:

【中文标题】Python:如何将日期时间/时间戳从一个时区转换为另一个时区?【英文标题】:How do you convert a datetime/timestamp from one timezone to another timezone? 【发布时间】:2015-11-05 18:59:39 【问题描述】:

具体来说,给定我的服务器的时区(系统时间视角)和时区输入,我如何计算系统时间,就好像它在那个新时区中一样(不管夏令时等)?

import datetime
current_time = datetime.datetime.now() #system time

server_timezone = "US/Eastern"
new_timezone = "US/Pacific"

current_time_in_new_timezone = ???

【问题讨论】:

【参考方案1】:

如果你知道你的原始时区和你想将它转换成的新时区,结果是非常简单的:

    制作两个pytz.timezone 对象,一个用于当前时区,一个用于新时区,例如pytz.timezone("US/Pacific")。您可以在pytz 库中找到所有官方时区的列表:import pytz; pytz.all_timezones

    将感兴趣的日期时间/时间戳本地化到当前时区,例如

current_timezone = pytz.timezone("US/Eastern")
localized_timestamp = current_timezone.localize(timestamp)
    在步骤 2 中新本地化的日期时间/时间戳上使用 .astimezone() 转换为新时区,并将所需时区的 pytz 对象作为输入,例如localized_timestamp.astimezone(new_timezone)

完成!

作为一个完整的例子:

import datetime
import pytz

# a timestamp I'd like to convert
my_timestamp = datetime.datetime.now()

# create both timezone objects
old_timezone = pytz.timezone("US/Eastern")
new_timezone = pytz.timezone("US/Pacific")

# two-step process
localized_timestamp = old_timezone.localize(my_timestamp)
new_timezone_timestamp = localized_timestamp.astimezone(new_timezone)

# or alternatively, as an one-liner
new_timezone_timestamp = old_timezone.localize(my_timestamp).astimezone(new_timezone) 

奖励:但如果您只需要特定时区的当前时间,您可以方便地将该时区直接传递到 datetime.now() 以直接获取当前时间:

datetime.datetime.now(new_timezone)

当涉及到一般需要时区转换时,我强烈建议您将数据库中的所有时间戳都以 UTC 格式存储,因为它没有夏令时 (DST) 转换。作为一种好的做法,应该始终选择启用时区支持(即使您的用户都在一个时区中!)。这将帮助您避免困扰当今众多软件的 DST 转换问题。

除了夏令时,软件时间通常会非常棘手。要了解在软件中处理时间有多么困难,这里有一个可能很有启发性的资源:@​​987654321@

即使是将日期时间/时间戳转换为日期这样看似简单的操作也可能变得不明显。正如this helpful documentation 指出的那样:

日期时间表示时间点。这是绝对的:它不依赖于任何东西。相反,日期是一个日历概念。这是一个时间段,其范围取决于考虑日期的时区。如您所见,这两个概念根本不同。

了解这种差异是避免基于时间的错误的关键一步。祝你好运。

【讨论】:

(1) 如果需要当前时间,请使用datetime.now(server_timezone) 而不是server_timezone.localize(datetime.now()) (2) 考虑使用is_dst 参数 (3) 在server_timezone.localize() 之后可能需要server_timezone.normalize(),修复不存在的当地时间。见more details and references in my answer 我相信在你的例子中'timezone_localized_timestamp'应该是'localized_timestamp'。或相反亦然。否则完美运行。 由于这个问题/答案是最佳结果,我想通知pytz 不再推荐。请参阅:blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html 和 talkpython.fm/episodes/show/271/…【参考方案2】:

如何将日期时间/时间戳从一个时区转换为另一个时区?

有两个步骤:

    根据系统时间和时区创建可感知的日期时间对象,例如,获取给定时区的当前系统时间:

    #!/usr/bin/env python
    from datetime import datetime
    import pytz
    
    server_timezone = pytz.timezone("US/Eastern")
    server_time = datetime.now(server_timezone) # you could pass *tz* directly
    

    注意:datetime.now(server_timezone) works even during ambiguous times 例如,在 DST 转换期间,server_timezone.localize(datetime.now()) 可能会失败(50% 的机会)。

    如果您确定您的输入时间存在于服务器的时区中并且是唯一的,那么您可以通过 is_dst=None 断言:

    server_time = server_timezone.localize(naive_time, is_dst=None)
    

    它会针对无效时间引发异常。 如果可以忽略最多 一天 错误(尽管由于 DST 导致的错误通常在 一个小时 左右),那么您可以删除 is_dst 参数:

    server_time = server_timezone.normalize(server_timezone.localize(naive_time))
    

    .normalize() 被调用来调整不存在的时间(本地时间在间隙中,在“弹簧向前”转换期间)。如果时区规则没有改变;您的服务器不应生成不存在的时间。见"Can I just always set is_dst=True?"

    将感知的日期时间对象转换为目标时区tz

    tz = pytz.timezone("US/Pacific")
    server_time_in_new_timezone = server_time.astimezone(tz)
    

【讨论】:

【参考方案3】:

使用 Python 3.9,标准库可以满足您的所有需求:zoneinfo。 pytz 不再需要(已弃用;-> pytz deprecation shim)。

例如:

from datetime import datetime
from zoneinfo import ZoneInfo

server_timezone = "US/Eastern"
new_timezone = "US/Pacific"

current_time = datetime.now(ZoneInfo(server_timezone)) 

# current_time_in_new_timezone = ???
current_time_in_new_timezone = current_time.astimezone(ZoneInfo(new_timezone))

这给了你例子

print(current_time.isoformat(timespec='seconds'))
# 2021-10-04T02:42:54-04:00

print(repr(current_time))
# datetime.datetime(2021, 10, 4, 2, 42, 54, 40600, tzinfo=zoneinfo.ZoneInfo(key='US/Eastern'))

print(current_time_in_new_timezone.isoformat(timespec='seconds'))
# 2021-10-03T23:42:54-07:00

print(repr(current_time_in_new_timezone))
# datetime.datetime(2021, 10, 3, 23, 42, 54, 40600, tzinfo=zoneinfo.ZoneInfo(key='US/Pacific'))

【讨论】:

以上是关于Python:如何将日期时间/时间戳从一个时区转换为另一个时区?的主要内容,如果未能解决你的问题,请参考以下文章

python - 如何在没有dateutil的情况下将时区感知字符串转换为Python中的日期时间?

将特定时区中的日期转换为 Python 中的时间戳

如何将字符串转换为时间,使其具有时区意识,并在 Python 中转换时区?

Python 字符串到 Django 时区(知道日期时间)

如何将日期/时间从 GMT 转换为本地时区

如何在 Python 中将美国/东部时区转换为美国/中部