【问题标题】:Python Timezone conversionPython时区转换
【发布时间】:2012-06-15 09:20:51
【问题描述】:

我正在寻找一种快速输入时间的方法,然后 python 将其转换为其他时区(可能多达 10 个不同的时区)

对不起。我根本不熟悉python中的时间,如果有人能把我引向正确的方向,我将不胜感激。

【问题讨论】:

标签: python timezone


【解决方案1】:

我发现最好的方法是将感兴趣的“时刻”转换为可识别 utc 时区的日期时间对象(在 python 中,datetime 对象不需要时区组件)。

然后您可以使用astimezone 转换为感兴趣的时区(reference)。

from datetime import datetime
import pytz

utcmoment_naive = datetime.utcnow()
utcmoment = utcmoment_naive.replace(tzinfo=pytz.utc)

# print "utcmoment_naive: {0}".format(utcmoment_naive) # python 2
print("utcmoment_naive: {0}".format(utcmoment_naive))
print("utcmoment:       {0}".format(utcmoment))

localFormat = "%Y-%m-%d %H:%M:%S"

timezones = ['America/Los_Angeles', 'Europe/Madrid', 'America/Puerto_Rico']

for tz in timezones:
    localDatetime = utcmoment.astimezone(pytz.timezone(tz))
    print(localDatetime.strftime(localFormat))

# utcmoment_naive: 2017-05-11 17:43:30.802644
# utcmoment:       2017-05-11 17:43:30.802644+00:00
# 2017-05-11 10:43:30
# 2017-05-11 19:43:30
# 2017-05-11 13:43:30

因此,在本地时区感兴趣的时刻(exists 的时间),您可以像这样将其转换为 utc (reference)。

localmoment_naive = datetime.strptime('2013-09-06 14:05:10', localFormat)

localtimezone = pytz.timezone('Australia/Adelaide')

try:
    localmoment = localtimezone.localize(localmoment_naive, is_dst=None)
    print("Time exists")

    utcmoment = localmoment.astimezone(pytz.utc)

except pytz.exceptions.NonExistentTimeError as e:
    print("NonExistentTimeError")

【讨论】:

  • 请注意,本地时间可能不明确,并且给定的字符串可能与任何现有时间不对应,例如,由于 DST 转换。如果您想在这种情况下引发异常,请提供 localize(is_dst=None)
  • 要把这个答案保存在某个地方,因为我想我每周至少会参考它两次:P
【解决方案2】:

使用pytz

from datetime import datetime
from pytz import timezone

fmt = "%Y-%m-%d %H:%M:%S %Z%z"
timezonelist = ['UTC','US/Pacific','Europe/Berlin']
for zone in timezonelist:

    now_time = datetime.now(timezone(zone))
    print now_time.strftime(fmt)

【讨论】:

  • 注意:它在不同时区打印不同时刻。 OP 询问不同时区的相同时刻。
  • @jfs 不,它没有 - 我刚刚运行它,它打印了 2018-07-12 13:46:17 UTC+00002018-07-12 06:46:17 PDT-07002018-07-12 15:46:17 CEST+0200,所有这些都代表同一时刻。
  • @MarkAmery:尝试向fmt ("%f") 添加微秒以查看时间实例是否不同。
  • @jfs 啊,我误解了你的评论!我以为你是在断言这些时刻代表了完全不同的时刻(即相隔几个小时),而不仅仅是它们在 datetime.now(...) 调用之间被几微秒分开。
【解决方案3】:
import datetime
import pytz

def convert_datetime_timezone(dt, tz1, tz2):
    tz1 = pytz.timezone(tz1)
    tz2 = pytz.timezone(tz2)

    dt = datetime.datetime.strptime(dt,"%Y-%m-%d %H:%M:%S")
    dt = tz1.localize(dt)
    dt = dt.astimezone(tz2)
    dt = dt.strftime("%Y-%m-%d %H:%M:%S")

    return dt

-

  • dt: 日期时间字符串
  • tz1:初始时区
  • tz2:目标时区

-

> convert_datetime_timezone("2017-05-13 14:56:32", "Europe/Berlin", "PST8PDT")
'2017-05-13 05:56:32'

> convert_datetime_timezone("2017-05-13 14:56:32", "Europe/Berlin", "UTC")
'2017-05-13 12:56:32'

-

> pytz.all_timezones[0:10]
['Africa/Abidjan',
 'Africa/Accra',
 'Africa/Addis_Ababa',
 'Africa/Algiers',
 'Africa/Asmara',
 'Africa/Asmera',
 'Africa/Bamako',
 'Africa/Bangui',
 'Africa/Banjul',
 'Africa/Bissau']

【讨论】:

    【解决方案4】:

    Python 3.9 添加了zoneinfo 模块,所以现在只需要标准库!

    >>> from zoneinfo import ZoneInfo
    >>> from datetime import datetime
    
    >>> d = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo('America/Los_Angeles'))
    >>> d.astimezone(ZoneInfo('Europe/Berlin'))  # 12:00 in Cali will be 20:00 in Berlin
    datetime.datetime(2020, 10, 31, 20, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Berlin'))
    

    Wikipedia list of available time zones


    now()utcnow() 等一些函数返回时区未知的日期时间,这意味着它们不包含时区信息。我建议只使用关键字tz=ZoneInfo('localtime') 向他们请求时区感知值。

    如果astimezone 得到一个不知道时区的输入,它会假定它是当地时间,这可能会导致错误:

    >>> datetime.utcnow()  # UTC -- NOT timezone-aware!!
    datetime.datetime(2020, 6, 1, 22, 39, 57, 376479)
    >>> datetime.now()     # Local time -- NOT timezone-aware!!
    datetime.datetime(2020, 6, 2, 0, 39, 57, 376675)
    
    >>> datetime.now(tz=ZoneInfo('localtime'))  # timezone-aware
    datetime.datetime(2020, 6, 2, 0, 39, 57, 376806, tzinfo=zoneinfo.ZoneInfo(key='localtime'))
    >>> datetime.now(tz=ZoneInfo('Europe/Berlin'))  # timezone-aware
    datetime.datetime(2020, 6, 2, 0, 39, 57, 376937, tzinfo=zoneinfo.ZoneInfo(key='Europe/Berlin'))
    >>> datetime.utcnow().astimezone(ZoneInfo('Europe/Berlin'))  # WRONG!!
    datetime.datetime(2020, 6, 1, 22, 39, 57, 377562, tzinfo=zoneinfo.ZoneInfo(key='Europe/Berlin'))
    

    Windows has no系统时区数据库,所以这里需要一个额外的包:

    pip install tzdata  
    

    有一个允许在 Python 3.6 到 3.8 中使用的向后移植:

    sudo pip install backports.zoneinfo
    

    然后:

    from backports.zoneinfo import ZoneInfo
    

    【讨论】:

      【解决方案5】:

      要在 Python 中将一个时区的时间转换为另一个时区,您可以use datetime.astimezone():

      time_in_new_timezone = time_in_old_timezone.astimezone(new_timezone)
      

      给定aware_dt(某个时区的datetime对象),将其转换为其他时区并以给定的时间格式打印时间:

      #!/usr/bin/env python3
      import pytz  # $ pip install pytz
      
      time_format = "%Y-%m-%d %H:%M:%S%z"
      tzids = ['Asia/Shanghai', 'Europe/London', 'America/New_York']
      for tz in map(pytz.timezone, tzids):
          time_in_tz = aware_dt.astimezone(tz)
          print(f"{time_in_tz:{time_format}}")
      

      如果f""语法不可用,你可以用"".format(**vars())替换它

      您可以从本地时区的当前时间设置aware_dt

      from datetime import datetime
      import tzlocal  # $ pip install tzlocal
      
      local_timezone = tzlocal.get_localzone()
      aware_dt = datetime.now(local_timezone) # the current time
      

      或者从本地时区的输入时间字符串:

      naive_dt = datetime.strptime(time_string, time_format)
      aware_dt = local_timezone.localize(naive_dt, is_dst=None)
      

      time_string 可能看起来像:'2016-11-19 02:21:42'。对应time_format = '%Y-%m-%d %H:%M:%S'

      is_dst=None 如果输入时间字符串对应于不存在或不明确的本地时间(例如在 DST 转换期间),则强制异常。你也可以通过is_dst=Falseis_dst=True。在Python: How do you convert datetime/timestamp from one timezone to another timezone?查看更多详细信息的链接

      【讨论】:

        【解决方案6】:

        时间换算

        要在 Python 中将一个时区的时间转换为另一个时区,您可以使用 datetime.astimezone():

        所以,下面的代码是将本地时间转换为其他时区。

        • datetime.datetime.today() - 返回当前当地时间
        • datetime.astimezone() - 转换时区,但我们必须通过时区。
        • pytz.timezone('Asia/Kolkata') - 将时区传递给 pytz 模块
        • Strftime - 将日期时间转换为字符串
        # Time conversion from local time
        import datetime
        import pytz
        dt_today = datetime.datetime.today()   # Local time
        dt_India = dt_today.astimezone(pytz.timezone('Asia/Kolkata')) 
        dt_London = dt_today.astimezone(pytz.timezone('Europe/London'))
        India = (dt_India.strftime('%m/%d/%Y %H:%M'))
        London = (dt_London.strftime('%m/%d/%Y %H:%M'))
        print("Indian standard time: "+India+" IST")
        print("British Summer Time: "+London+" BST")
        

        列出所有时区

        import pytz
        for tz in pytz.all_timezones:
            print(tz)
        

        【讨论】:

          【解决方案7】:

          对于 Python 时区转换,我使用来自 Taavi Burns 的 PyCon 2012 presentation 中的 handy table

          【讨论】:

            【解决方案8】:

            请注意:这个答案的第一部分是或版本 1.x 的 pendulum。有关 2.x 版本的答案,请参见下文。

            希望我不会太迟!

            pendulum 库擅长这种和其他日期时间计算。

            >>> import pendulum
            >>> some_time_zones = ['Europe/Paris', 'Europe/Moscow', 'America/Toronto', 'UTC', 'Canada/Pacific', 'Asia/Macao']
            >>> heres_a_time = '1996-03-25 12:03 -0400'
            >>> pendulum_time = pendulum.datetime.strptime(heres_a_time, '%Y-%m-%d %H:%M %z')
            >>> for tz in some_time_zones:
            ...     tz, pendulum_time.astimezone(tz)
            ...     
            ('Europe/Paris', <Pendulum [1996-03-25T17:03:00+01:00]>)
            ('Europe/Moscow', <Pendulum [1996-03-25T19:03:00+03:00]>)
            ('America/Toronto', <Pendulum [1996-03-25T11:03:00-05:00]>)
            ('UTC', <Pendulum [1996-03-25T16:03:00+00:00]>)
            ('Canada/Pacific', <Pendulum [1996-03-25T08:03:00-08:00]>)
            ('Asia/Macao', <Pendulum [1996-03-26T00:03:00+08:00]>)
            

            Answer 列出了可用于 pendulum 的时区名称。 (它们与 pytz 相同。)

            对于版本 2:

            • some_time_zones 是可能在程序中使用的时区名称列表
            • heres_a_time 是一个示例时间,包含一个格式为“-0400”的时区
            • 我首先将时间转换为钟摆时间以进行后续处理
            • 现在我可以在show_time_zones 中显示每个时区的时间

            ...

            >>> import pendulum
            >>> some_time_zones = ['Europe/Paris', 'Europe/Moscow', 'America/Toronto', 'UTC', 'Canada/Pacific', 'Asia/Macao']
            >>> heres_a_time = '1996-03-25 12:03 -0400'
            >>> pendulum_time = pendulum.from_format('1996-03-25 12:03 -0400', 'YYYY-MM-DD hh:mm ZZ')
            >>> for tz in some_time_zones:
            ...     tz, pendulum_time.in_tz(tz)
            ...     
            ('Europe/Paris', DateTime(1996, 3, 25, 17, 3, 0, tzinfo=Timezone('Europe/Paris')))
            ('Europe/Moscow', DateTime(1996, 3, 25, 19, 3, 0, tzinfo=Timezone('Europe/Moscow')))
            ('America/Toronto', DateTime(1996, 3, 25, 11, 3, 0, tzinfo=Timezone('America/Toronto')))
            ('UTC', DateTime(1996, 3, 25, 16, 3, 0, tzinfo=Timezone('UTC')))
            ('Canada/Pacific', DateTime(1996, 3, 25, 8, 3, 0, tzinfo=Timezone('Canada/Pacific')))
            ('Asia/Macao', DateTime(1996, 3, 26, 0, 3, 0, tzinfo=Timezone('Asia/Macao')))
            

            【讨论】:

            • AttributeError: 'function' 对象没有属性 'strptime'
            • Pendulum 很棒,但请记住,输出可能与您接下来想做的任何事情都不兼容,例如 Pandas 数据帧。
            【解决方案9】:

            对于 Python 3.2+,simple-date 是 pytz 的包装器,它试图简化事情。

            如果你有time 那么

            SimpleDate(time).convert(tz="...")
            

            可以做你想做的事。但是时区是相当复杂的东西,因此它可能会变得更加复杂 - 请参阅the docs

            【讨论】:

              【解决方案10】:
              # Program
              import time
              import os
              
              os.environ['TZ'] = 'US/Eastern'
              time.tzset()
              print('US/Eastern in string form:',time.asctime()) 
              
              os.environ['TZ'] = 'Australia/Melbourne'
              time.tzset()
              print('Australia/Melbourne in string form:',time.asctime())
              
              os.environ['TZ'] = 'Asia/Kolkata'
              time.tzset()
              print('Asia/Kolkata in string form:',time.asctime()) 
              

              【讨论】:

              • 您好,欢迎来到 Stack Overflow!请阅读How to Answer 并始终记住,您不仅要回答 OP,还要回答这个问题的任何未来读者,特别是考虑到这个问题已经 8 岁了。请edit你的帖子包含一些解释为什么这会起作用。
              • @Sahil Soni - 请提供正确描述和解释的答案
              猜你喜欢
              • 1970-01-01
              • 2013-11-24
              • 2019-04-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-03-03
              • 2021-04-16
              • 1970-01-01
              相关资源
              最近更新 更多