Перетворення часового поясу Python


81

Я шукаю швидкий спосіб набору часу, а потім python перетворить його в інші часові пояси (можливо, до 10 різних часових поясів)

Вибачте. Я взагалі не знайомий з часом у python, якби хтось міг спрямувати мене в правильному напрямку, я б це дуже вдячний.


Python 3.9: zoneinfo
MrFuppes

Відповіді:


103

Я виявив , що найкращий підхід полягає в перетворення «моменту» інтерес до-годинний пояс UTC-Aware об'єкт дати і часу (в пітона, компонент часового поясу не потрібно для дати і часу об'єктів).

Тоді ви можете використовувати астимезон для перетворення часового поясу, що представляє інтерес ( посилання ).

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

Отже, з моментом зацікавленості в місцевому часовому поясі (час, який існує ), ви перетворюєте його на utc таким чином ( посилання ).

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

6
будьте уважні, місцевий час може бути неоднозначним, і заданий рядок може не відповідати будь-якому існуючому часу, наприклад через перехід на літній час. Вкажіть, localize(is_dst=None)чи хочете ви зробити виняток у таких випадках.
jfs

55

Використання 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)

10
Примітка: він друкує різні моменти часу в різних часових поясах. OP запитує приблизно однаковий момент часу в різних часових поясах.
jfs

@jfs Ні , це не робить - я просто побіг це і надруковане 2018-07-12 13:46:17 UTC+0000, 2018-07-12 06:46:17 PDT-0700і 2018-07-12 15:46:17 CEST+0200, всі з яких представляють собою один і той же момент часу.
Mark Amery

@MarkAmery: спробуйте додати мікросекунди до fmt( "%f"), щоб побачити, що екземпляри часу відрізняються.
jfs

1
@jfs Ах, я неправильно зрозумів ваш коментар! Я думав, ви стверджуєте, що моменти представляють абсолютно різні моменти в часі (тобто, з інтервалом у годинах), а не лише про те, що між datetime.now(...)дзвінками їх розділяло кілька мікросекунд .
Mark Amery

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

8

Щоб перетворити час в одному часовому поясі в інший часовий пояс в Python, ви можете використовувати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змушує виняток, якщо вхідний рядок часу відповідає неіснуючому або неоднозначному місцевому часу, наприклад під час переходу на літній час. Крім того, можна пройти is_dst=False, is_dst=True. Див. Посилання з більш докладною інформацією на Python: Як перетворити дату / час відмітки з одного часового поясу в інший часовий пояс?



5

Зверніть увагу: перша частина цієї відповіді - це або версія 1.x маятника. Відповідь на версію 2.x див. Нижче.

Сподіваюся, я не запізнився!

Бібліотека маятника перевершує цю та інші обчислення дати та часу.

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

Відповідь перелічує назви часових поясів, які можна використовувати з маятником. (Вони такі ж, як для 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'
Сет Коннелл

1
Маятник дивовижний, але майте на увазі, вихід може бути несумісний з тим, що ви хочете зробити далі, наприклад, з рамками даних Pandas.
Туранга, 1

5

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

Список доступних часових поясів у Вікіпедії


Деякі функції, такі як 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 не має бази даних системного часового поясу, тому тут потрібен додатковий пакет:

pip install tzdata  

Існує бекпорт, який дозволяє використовувати в Python 3.6 - 3.8 :

sudo pip install backports.zoneinfo

Тоді:

from backports.zoneinfo import ZoneInfo

3

Перетворення часу

Для перетворення часу в одному часовому поясі в інший часовий пояс в Python ви можете використовувати datetime.astimezone ():

отже, нижче код - це перетворення місцевого часу в інший часовий пояс.

  • datetime.datetime.today () - повернення поточного місцевого часу
  • datetime.astimezone () - перетворення часового поясу, але нам потрібно передати часовий пояс.
  • pytz.timezone ('Азія / Колката') - передача часового поясу модулю pytz
  • Strftime - перетворення Datetime у рядок
# 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)

2

Для Python 3.2+ simple-date - це обгортка навколо pytz, яка намагається спростити речі.

Якщо у вас є timeтоді

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

може робити те, що ти хочеш. Але часові пояси - це досить складні речі, тому це може значно ускладнитися - див . Документацію .


0
# 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()) 

2
Привіт та ласкаво просимо до Stack Overflow! Будь ласка, прочитайте « Як відповісти» та завжди пам’ятайте, що ви відповідаєте не лише ОП, а й майбутнім читачам цього питання, особливо враховуючи, що цьому вже виповнилося 8 років. Будь ласка, відредагуйте свою публікацію, щоб містити пояснення щодо того, чому це може працювати.
Адріан

@Sahil Soni - Будь ласка, надайте відповіді з належними описами та поясненнями
Saikat Saha
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.