【问题标题】:How do you convert a datetime/timestamp from one timezone to another timezone?Python:如何将日期时间/时间戳从一个时区转换为另一个时区?
【发布时间】: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 = ???

【问题讨论】:

    标签: python datetime timezone pytz timedelta


    【解决方案1】:

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

    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 转换问题。

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

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

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

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

    【讨论】:

    【解决方案2】:

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

    有两个步骤:

    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) 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?"

    2. 将感知的日期时间对象转换为目标时区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'))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-06
        • 2012-01-30
        • 2010-11-26
        • 2018-02-19
        • 2019-06-19
        • 2011-03-11
        相关资源
        最近更新 更多