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中的日期时间?