Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Работа с временными зонами в Python
Время и часовые пояса — одна из самых сложных задач в программировании. Python предоставляет несколько инструментов для работы с ними правильно.
Основные понятия
Naive и Aware datetime
from datetime import datetime
import pytz
# Naive datetime — без информации о временной зоне
naive_dt = datetime(2024, 3, 22, 14, 30, 0)
print(naive_dt.tzinfo) # None
print(naive_dt.isoformat()) # '2024-03-22T14:30:00'
# Aware datetime — с информацией о временной зоне
aware_dt = datetime(2024, 3, 22, 14, 30, 0, tzinfo=pytz.UTC)
print(aware_dt.tzinfo) # UTC
print(aware_dt.isoformat()) # '2024-03-22T14:30:00+00:00'
Получение текущего времени
✓ Правильный способ — UTC
from datetime import datetime, timezone
# Получить текущее UTC время (Aware)
current_utc = datetime.now(timezone.utc)
print(current_utc) # 2024-03-22 12:45:30.123456+00:00
# Это предпочтительный способ — не зависит от системного времени
✗ Неправильный способ
# Не используй это!
naive_now = datetime.now() # Naive datetime, ненадёжно
utc_now = datetime.utcnow() # DEPRECATED в Python 3.12+
Работа с временными зонами (pytz)
import pytz
from datetime import datetime
# Получить список всех временных зон
print(pytz.all_timezones) # выведет все зоны
# Создать datetime с конкретной зоной
moscow_tz = pytz.timezone('Europe/Moscow')
dt_moscow = moscow_tz.localize(datetime(2024, 3, 22, 14, 30, 0))
print(dt_moscow) # 2024-03-22 14:30:00+03:00
# Или через replace (менее надёжный способ)
dt_moscow = datetime(2024, 3, 22, 14, 30, 0, tzinfo=moscow_tz)
Преобразование между зонами
from datetime import datetime, timezone
import pytz
# Создать время в UTC
utc_time = datetime(2024, 3, 22, 12, 0, 0, tzinfo=pytz.UTC)
print(f"UTC: {utc_time}") # 2024-03-22 12:00:00+00:00
# Преобразовать в другую зону
moscow_tz = pytz.timezone('Europe/Moscow')
moscow_time = utc_time.astimezone(moscow_tz)
print(f"Moscow: {moscow_time}") # 2024-03-22 15:00:00+03:00
# Преобразовать в токийское время
tokyo_tz = pytz.timezone('Asia/Tokyo')
tokyo_time = utc_time.astimezone(tokyo_tz)
print(f"Tokyo: {tokyo_time}") # 2024-03-22 21:00:00+09:00
Работа с zoneinfo (Python 3.9+)
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
# Новый способ (рекомендуется для Python 3.9+)
moscow_tz = ZoneInfo("Europe/Moscow")
dt_moscow = datetime(2024, 3, 22, 14, 30, 0, tzinfo=moscow_tz)
print(dt_moscow) # 2024-03-22 14:30:00+03:00
# Преобразование
utc_time = datetime(2024, 3, 22, 12, 0, 0, tzinfo=ZoneInfo("UTC"))
tokyo_time = utc_time.astimezone(ZoneInfo("Asia/Tokyo"))
print(tokyo_time) # 2024-03-22 21:00:00+09:00
Парсинг строк с временем
from datetime import datetime
from zoneinfo import ZoneInfo
import dateutil.parser
# Стандартный способ
dt_str = "2024-03-22T14:30:00+03:00"
dt = datetime.fromisoformat(dt_str)
print(dt) # 2024-03-22 14:30:00+03:00
# Более гибкий парсинг с dateutil
dt = dateutil.parser.isoparse("2024-03-22T14:30:00+03:00")
dt = dateutil.parser.parse("22 March 2024 at 2:30 PM") # Гибкий парсинг
print(dt) # 2024-03-22 14:30:00
Работа с текущим временем в разных зонах
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
# Текущее время в UTC
now_utc = datetime.now(timezone.utc)
print(f"UTC: {now_utc}")
# Текущее время в конкретной зоне
now_moscow = datetime.now(ZoneInfo("Europe/Moscow"))
print(f"Moscow: {now_moscow}")
now_tokyo = datetime.now(ZoneInfo("Asia/Tokyo"))
print(f"Tokyo: {now_tokyo}")
Сравнение datetime с разными зонами
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
# Создать два времени в разных зонах
dt1 = datetime(2024, 3, 22, 12, 0, 0, tzinfo=timezone.utc)
dt2 = datetime(2024, 3, 22, 15, 0, 0, tzinfo=ZoneInfo("Europe/Moscow"))
# Сравнение автоматически учитывает временные зоны
print(dt1 == dt2) # True! Оба представляют одно время
print(dt1 < dt2) # False
Работа с базой данных
PostgreSQL (рекомендуется)
from datetime import datetime, timezone
from sqlalchemy import Column, DateTime
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class Event(Base):
__tablename__ = "events"
# TIMESTAMPTZ — хранит время с информацией о зоне
created_at = Column(DateTime(timezone=True), default=datetime.now(timezone.utc))
# При работе с БД — всегда используй UTC
event = Event(created_at=datetime.now(timezone.utc))
session.add(event)
session.commit()
# При получении из БД — конвертируй в нужную зону
local_time = event.created_at.astimezone(ZoneInfo("Europe/Moscow"))
Сериализация для API (JSON)
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
import json
# ✓ Правильно — сохранять ISO 8601 с UTC
dt = datetime.now(timezone.utc)
iso_string = dt.isoformat() # '2024-03-22T12:45:30.123456+00:00'
json_data = json.dumps({"timestamp": iso_string})
# ✓ При получении — парсить и конвертировать
data = json.loads(json_data)
dt_received = datetime.fromisoformat(data["timestamp"])
local_time = dt_received.astimezone(ZoneInfo("Europe/Moscow"))
# ✗ Не делай это — отправлять naive datetime
# naive_dt = datetime.now() # ПЛОХО!
Django ORM
# settings.py
USE_TZ = True # ВСЕГДА True для работы с временными зонами
TIME_ZONE = 'Europe/Moscow' # Зона для отображения в админке
# models.py
from django.db import models
from django.utils import timezone
class Article(models.Model):
# DateTimeField автоматически создаёт TIMESTAMPTZ
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# views.py
from django.utils import timezone
# Получить текущее время
now = timezone.now() # Всегда UTC, aware
# Сравнивать с timezone-aware datetime
articles = Article.objects.filter(created_at__gt=timezone.now())
FastAPI
from datetime import datetime, timezone
from pydantic import BaseModel, Field
from fastapi import FastAPI
app = FastAPI()
class EventSchema(BaseModel):
name: str
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
@app.post("/events")
async def create_event(event: EventSchema):
# Pydantic автоматически парсит ISO 8601
return event
# Клиент отправляет: {"name": "test", "created_at": "2024-03-22T12:00:00+00:00"}
Лучшие практики
# ✓ ПРАВИЛЬНО
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
# Используй UTC везде в коде
now = datetime.now(timezone.utc)
# Конвертируй в локальное время только на границе (API, шаблон)
local_time = now.astimezone(ZoneInfo("Europe/Moscow"))
# Сохраняй в БД как UTC
db.save(created_at=now)
# Отправляй в API как ISO 8601
response = {"timestamp": now.isoformat()}
# ✗ НЕПРАВИЛЬНО
# datetime.now() # Naive datetime
# datetime.utcnow() # Deprecated
# now.replace(tzinfo=timezone.utc) # Неправильное преобразование!
# Хранить время как строку или число
Итого
Работа с временем в Python:
- Используй UTC везде в коде приложения
datetime.now(timezone.utc)— текущее времяzoneinfo.ZoneInfo(Python 3.9+) илиpytzдля работы с зонами- Конвертируй в локальное время только на границах (API, UI)
- Сохраняй в БД как UTC с типом TIMESTAMPTZ
- Отправляй в API как ISO 8601 строки
- Никогда не используй naive datetime в production