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

问题描述 投票:0回答:5

具体来说,给定我的服务器的时区(系统时间角度)和时区输入,我如何计算系统时间,就好像它处于新时区一样(无论夏令时等)?

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

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

current_time_in_new_timezone = ???
python datetime timezone pytz timedelta
5个回答
81
投票

如果您知道您的原始时区和要将其转换到的新时区,结果非常简单:

  1. 创建两个

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

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

current_timezone = pytz.timezone("US/Eastern")
localized_timestamp = current_timezone.localize(timestamp)
  1. 使用步骤 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 转换问题。

除了夏令时之外,软件中的时间通常非常棘手。为了了解在一般软件中处理时间有多么困难,这里有一个可能具有启发性的资源:http://yourcalendricalfallacyis.com

即使将日期时间/时间戳转换为日期这样看似简单的操作也可能变得不明显。正如这个有用的文档指出的:

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

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


30
投票
zoneinfo

。不再需要 pytz(已弃用;-> pytz 弃用垫片)。 例如:

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'))



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

有两个步骤:

  1. 根据系统时间和时区创建一个感知的日期时间对象

    ,例如,获取给定时区的当前系统时间: #!/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)即使在不明确的时间

    也能工作,例如,在夏令时转换期间,而
    server_timezone.localize(datetime.now())可能会失败(50%的机会)。
    
    
    如果您确定您的输入时间存在于服务器的时区中并且是唯一的,那么您可以通过

    is_dst=None

    来断言:

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

    它会引发无效时间的异常。
    如果可以忽略最多

    一天
    错误(尽管通常由于夏令时而导致的错误大约是一个小时),那么您可以删除is_dst参数:

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

    调用
    .normalize()

    来调整不存在的时间(间隙中的本地时间,在“向前弹簧”转换期间)。如果时区规则没有改变;您的服务器不应生成不存在的时间。请参阅

    “我可以始终设置 is_dst=True 吗?”

  2. 将感知日期时间对象转换为目标时区

    tz

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

    
        

1
投票

from datetime import datetime from zoneinfo import ZoneInfo from_timezone = ZoneInfo('Europe/Moscow') # UTC-3 to_timezone = ZoneInfo('Asia/Tbilisi') # UTC-4 dt = datetime.fromtimestamp(timestamp, to_timezone) result_timestamp = int(dt.replace(tzinfo=from_timezone).timestamp())

例如,如果您采用时间戳 = 529635600(莫斯科 1986-14-10 04:00:00)并运行此代码,您将得到 result_timestamp = 529639200(第比利斯 1986-14-10 05:00:00)。 


0
投票
FObersteiner

从 python 3.9 开始,代码可以简化: from datetime import datetime from zoneinfo import ZoneInfo current_time = datetime.datetime.now() #system time # server_timezone = "US/Eastern" new_timezone = ZoneInfo("US/Pacific") current_time_in_new_timezone = new_timezone.fromutc(current_time.astimezone(new_timezone))

就我个人的观点而言,在 python 中使用本地日期时间仍然相当模糊,但比前段时间好多了。

© www.soinside.com 2019 - 2024. All rights reserved.