Python 时区转换

如何在 Python 中将一个时区转换为另一个时区?

214203 次浏览

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

For Python timezone conversions, I use the handy table from the PyCon 2012 presentation by Taavi Burns.

I have found that the best approach is to convert the "moment" of interest to a utc-timezone-aware datetime object (in python, the timezone component is not required for datetime objects).

Then you can use astimezone to convert to the timezone of interest (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

So, with the moment of interest in the local timezone (a time that exists), you convert it to utc like this (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")

For Python 3.2+ simple-date is a wrapper around pytz that tries to simplify things.

If you have a time then

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

may do what you want. But timezones are quite complex things, so it can get significantly more complicated - see the the docs.

To convert a time in one timezone to another timezone in Python, you could use datetime.astimezone():

time_in_new_timezone = time_in_old_timezone.astimezone(new_timezone)

Given aware_dt (a datetime object in some timezone), to convert it to other timezones and to print the times in a given time format:

#!/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}}")

If f"" syntax is unavailable, you could replace it with "".format(**vars())

where you could set aware_dt from the current time in the local timezone:

from datetime import datetime
import tzlocal  # $ pip install tzlocal


local_timezone = tzlocal.get_localzone()
aware_dt = datetime.now(local_timezone) # the current time

Or from the input time string in the local timezone:

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

where time_string could look like: '2016-11-19 02:21:42'. It corresponds to time_format = '%Y-%m-%d %H:%M:%S'.

is_dst=None forces an exception if the input time string corresponds to a non-existing or ambiguous local time such as during a DST transition. You could also pass is_dst=False, is_dst=True. See links with more details at Python: How do you convert datetime/timestamp from one timezone to another timezone?

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: date time string
  • tz1: initial time zone
  • tz2: target time zone

-

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

Please note: The first part of this answer is or version 1.x of pendulum. See below for a version 2.x answer.

I hope I'm not too late!

The pendulum library excels at this and other date-time calculations.

>>> 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 lists the names of the time zones that may be used with pendulum. (They're the same as for pytz.)

For version 2:

  • some_time_zones is a list of the names of the time zones that might be used in a program
  • heres_a_time is a sample time, complete with a time zone in the form '-0400'
  • I begin by converting the time to a pendulum time for subsequent processing
  • now I can show what this time is in each of the time zones in 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')))

Python 3.9 adds the zoneinfo module so now only the the standard library is needed!

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


Some functions such as now() and utcnow() return timezone-unaware datetimes, meaning they contain no timezone information. I recommend only requesting timezone-aware values from them using the keyword tz=ZoneInfo('localtime').

If astimezone gets a timezone-unaware input, it will assume it is local time, which can lead to errors:

>>> 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 system time zone database, so here an extra package is needed:

pip install tzdata

There is a backport to allow use in Python 3.6 to 3.8:

sudo pip install backports.zoneinfo

Then:

from backports.zoneinfo import ZoneInfo

Time conversion

To convert a time in one timezone to another timezone in Python, you could use datetime.astimezone():

so, below code is to convert the local time to other time zone.

  • datetime.datetime.today() - return current the local time
  • datetime.astimezone() - convert the time zone, but we have to pass the time zone.
  • pytz.timezone('Asia/Kolkata') -passing the time zone to pytz module
  • Strftime - Convert Datetime to string
# 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")

List all the time zones

import pytz
for tz in pytz.all_timezones:
print(tz)
# 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())