Python: уроки, справочник и задачи

pytz Python: работа с часовыми поясами

Раздел: Модули и библиотеки Python · Обновлено 31.10.2026

Библиотека pytz для Python содержит базу часовых поясов IANA и позволяет переводить время между городами и странами с учетом летнего времени. В статье показано, как установить pytz, правильно создать дату в нужном поясе, перевести ее в другой и чем pytz отличается от встроенного модуля zoneinfo.

Pytz Python
Фото: calflier001 / CC BY-SA 2.0, Wikimedia Commons
Содержание статьи
  1. Установка и первый пример
  2. Поиск нужного часового пояса
  3. Главная ловушка: tzinfo вместо localize
  4. Перевод времени между поясами
  5. Летнее время и метод normalize
  6. Фиксированное смещение и исторические даты
  7. pytz или zoneinfo
  8. Частые вопросы
    1. Почему pytz показывает смещение +02:30 для Москвы?
    2. Как получить текущее время в UTC?
    3. Как убрать часовой пояс из даты?
    4. Нужно ли обновлять pytz?

Установка и первый пример

pytz не входит в стандартную библиотеку, его ставят через pip. Пакет написан на чистом Python и не имеет зависимостей, база поясов поставляется внутри него и обновляется с новыми версиями пакета.

pip install pytz

Самый короткий сценарий: получить текущее время в конкретном поясе. Для этого объект пояса передают в datetime.now().

from datetime import datetime
import pytz

moscow = pytz.timezone('Europe/Moscow')
now = datetime.now(moscow)
print(now.strftime('%d.%m.%Y %H:%M %Z'))  # например 08.03.2025 14:30 MSK

Пояса задаются именами вида Континент/Город: Europe/Moscow, Asia/Yekaterinburg, America/New_York. Сокращения вроде MSK или EST в качестве имени не подходят, так как они неоднозначны.

Поиск нужного часового пояса

В pytz есть несколько готовых списков. Они пригодятся, когда нужно показать пользователю выбор пояса или проверить, существует ли имя.

import pytz

print(pytz.country_timezones('ru')[:3])
# ['Europe/Kaliningrad', 'Europe/Moscow', 'Europe/Kirov']
print('Asia/Omsk' in pytz.common_timezones)  # True

try:
    pytz.timezone('Moscow')
except pytz.UnknownTimeZoneError:
    print('Нет такого пояса')

Главная ловушка: tzinfo вместо localize

Самая частая ошибка с pytz - передать пояс в конструктор datetime через параметр tzinfo. Так делать нельзя: pytz хранит всю историю смещений пояса, и без подсказки datetime берет самое первое из них, местное среднее время (LMT) конца XIX века.

from datetime import datetime
import pytz

msk = pytz.timezone('Europe/Moscow')
wrong = datetime(2022, 3, 27, 1, 30, tzinfo=msk)
right = msk.localize(datetime(2022, 3, 27, 1, 30))
print(wrong)  # 2022-03-27 01:30:00+02:30
print(right)  # 2022-03-27 01:30:00+03:00

Смещение +02:30 не имеет отношения к современной Москве. Правильный способ - создать наивную дату (без пояса) и вызвать метод localize(). Он выберет смещение, которое действовало именно в эту дату. Исключение одно: с pytz.utc параметр tzinfo работает корректно, у UTC нет истории изменений.

Перевод времени между поясами

Если дата уже осведомленная (aware), в другой пояс ее переводят стандартным методом astimezone(). Хранить и сравнивать время лучше в UTC, а в местное переводить только для показа пользователю.

from datetime import datetime
import pytz

meeting = datetime(2025, 7, 1, 12, 0, tzinfo=pytz.utc)
for name in ('Europe/Moscow', 'America/New_York', 'Asia/Tokyo'):
    local = meeting.astimezone(pytz.timezone(name))
    print(f'{name:18} {local:%H:%M %Z}')
# Europe/Moscow      15:00 MSK
# America/New_York   08:00 EDT
# Asia/Tokyo         21:00 JST

Так удобно выводить время вебинара или дедлайна для участников из разных городов. Для форматирования используется тот же синтаксис, что в strftime, код %Z подставляет сокращение пояса, а %z - смещение вида +0300.

Летнее время и метод normalize

В России сезонный перевод часов отменен, но в США и Европе он есть, и именно там pytz требует аккуратности. При арифметике через timedelta смещение у даты не пересчитывается само, даже если результат перешел через границу летнего времени.

from datetime import datetime, timedelta
import pytz

ny = pytz.timezone('America/New_York')
d = ny.localize(datetime(2024, 3, 10, 1, 30))
later = d + timedelta(hours=1)
print(later)                # 2024-03-10 02:30:00-05:00, такого времени нет
print(ny.normalize(later))  # 2024-03-10 03:30:00-04:00

Метод normalize() исправляет смещение после сложения или вычитания. Еще две проблемные ситуации - несуществующий час весной и повторяющийся час осенью. Параметр is_dst=None в localize() заставляет pytz не угадывать, а выбрасывать исключение.

try:
    ny.localize(datetime(2024, 3, 10, 2, 30), is_dst=None)
except pytz.NonExistentTimeError:
    print('Этого времени не было: часы перевели вперед')

try:
    ny.localize(datetime(2024, 11, 3, 1, 30), is_dst=None)
except pytz.AmbiguousTimeError:
    print('Это время было дважды')

Фиксированное смещение и исторические даты

Пояс с постоянным смещением без привязки к городу создается функцией pytz.FixedOffset(), аргумент задается в минутах. Имени вида UTC+5 в базе нет, вызов pytz.timezone('UTC+5') закончится ошибкой UnknownTimeZoneError.

from datetime import datetime
import pytz

plus5 = pytz.FixedOffset(300)
print(datetime(2025, 1, 1, 9, 0, tzinfo=plus5))  # 2025-01-01 09:00:00+05:00

ny = pytz.timezone('America/New_York')
print(ny.localize(datetime(1900, 1, 1)))  # 1900-01-01 00:00:00-04:56

Второй пример показывает, что база хранит историю: в 1900 году Нью-Йорк жил по местному времени со смещением -4:56. Это полезно при обработке архивных данных, где нужно точное время событий прошлых лет.

pytz или zoneinfo

С Python 3.9 в стандартной библиотеке есть модуль zoneinfo, который решает ту же задачу без ловушек pytz. Сам pytz находится в режиме поддержки, новых возможностей в него не добавляют.

Задачаpytzzoneinfo
Создать дату в поясеtz.localize(dt)datetime(..., tzinfo=ZoneInfo(name))
Арифметика через летнее времянужен normalize()работает сразу
Перевод в другой поясastimezone()astimezone()
Источник базы поясоввнутри пакетасистема или пакет tzdata
Версии Pythonлюбые3.9 и новее

В новом проекте выбирайте zoneinfo. pytz остается нужен при поддержке старого кода и в библиотеках, которые требуют именно его объекты, например в старых версиях Django и pandas. Подробнее о стандартных классах дат читайте в статье про модуль datetime, а разницу между датами разбирает материал о timedelta.

Частые вопросы

Короткие ответы на вопросы о pytz, которые задают чаще всего.

Почему pytz показывает смещение +02:30 для Москвы?

Пояс передан в конструктор datetime через tzinfo=. Pytz в этом случае подставляет историческое местное время. Создайте наивную дату и вызовите tz.localize(dt).

Как получить текущее время в UTC?

Вызовите datetime.now(pytz.utc) или без pytz datetime.now(timezone.utc) из модуля datetime. Метод datetime.utcnow() устарел с Python 3.12 и возвращает наивную дату.

Как убрать часовой пояс из даты?

Вызовите dt.replace(tzinfo=None). Время останется прежним, исчезнет только информация о поясе. Если нужно наивное время в UTC, сначала переведите дату через astimezone(pytz.utc).

Нужно ли обновлять pytz?

Да, правила часовых поясов меняются правительствами разных стран несколько раз в год. Свежая база приходит с новой версией пакета: pip install -U pytz.