Работа с датой и временем в Python: DateTime, форматирование, часовые пояса

В Python для работы с датой и временем используют модуль datetime. Он покрывает основные сценарии: хранение, вычисления, форматирование и учёт часовых поясов. Ниже — практические примеры без лишней теории.


Базовые типы: date, time, datetime

  • date — только дата (год, месяц, день).
  • time — только время (часы, минуты, секунды).
  • datetime — дата и время вместе.

Примеры создания:

python
from datetime import date, time, datetime
 
d = date(2025, 7, 15)
t = time(14, 30, 5)
dt = datetime(2025, 7, 15, 14, 30, 5)
 
print(d)          # 2025-07-15
print(t)          # 14:30:05
print(dt)         # 2025-07-15 14:30:05

Часто используют datetime.now() для текущей даты и времени:

python
now = datetime.now()
print(now)

Получение отдельных частей даты

У объектов есть атрибуты, по которым удобно брать отдельные значения:

python
dt = datetime(2025, 7, 15, 14, 30, 5)
 
print(dt.year)    # 2025
print(dt.month)   # 7
print(dt.day)     # 15
print(dt.hour)    # 14
print(dt.minute)  # 30
print(dt.second)  # 5

Это полезно, когда нужно отдельно проверить год, месяц и т. п.


Форматирование: strftime и разбор строки: strptime

Форматирование в строку (strftime)

Превращаем datetime в строку по шаблону:

python
dt = datetime(2025, 7, 15, 14, 30, 5)
s = dt.strftime("%Y-%m-%d %H:%M:%S")
print(s)  # 2025-07-15 14:30:05

Частые коды формата:

  • %Y — год (4 цифры), %y — год (2 цифры)
  • %m — месяц (01–12), %d — день (01–31)
  • %H — час (00–23), %M — минуты, %S — секунды
  • %B — полное название месяца, %b — сокращённое
  • %A — полное название дня недели, %a — сокращённое

Пример с разными форматами:

python
dt = datetime.now()
 
print(dt.strftime("%d.%m.%Y"))                # 15.07.2025
print(dt.strftime("%B %d, %Y"))              # July 15, 2025
print(dt.strftime("%A, %d %B %Y, %H:%M"))   # Tuesday, 15 July 2025, 14:30

Разбор строки в datetime (strptime)

Когда дата приходит как текст (из файла, API, формы), её нужно превратить в объект:

python
s = "2025-07-15 14:30:05"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
print(dt, type(dt))  # datetime.datetime объект

Важно: шаблон должен точно соответствовать строке, иначе будет ValueError.


Вычисления с датами: timedelta

Для прибавления/вычитания дней, часов и т. д. используют timedelta:

python
from datetime import datetime, timedelta
 
now = datetime.now()
tomorrow = now + timedelta(days=1)
week_ago = now - timedelta(weeks=1)
three_hours_later = now + timedelta(hours=3)
 
print("Сейчас:", now)
print("Завтра:", tomorrow)
print("Неделю назад:", week_ago)
print("Через 3 часа:", three_hours_later)

timedelta поддерживает: days, seconds, microseconds, milliseconds, minutes, hours, weeks.

Пример: посчитать разницу между двумя датами:

python
start = datetime(2025, 7, 1, 10, 0)
end = datetime(2025, 7, 3, 14, 30)
diff = end - start
 
print(diff)                 # 2 days, 4:30:00
print(diff.total_seconds())# общее число секунд
print(diff.days)            # только дни

Часовые пояса: naive и aware объекты

Есть два типа datetime:

  • naive — без часового пояса (по умолчанию).
  • aware — с часовым поясом (более правильный вариант для реальных систем).

Простой способ (Python 3.9+): zoneinfo

python
from datetime import datetime
from zoneinfo import ZoneInfo
 
# Москва
dt_msk = datetime(2025, 7, 15, 12, 0, tzinfo=ZoneInfo("Europe/Moscow"))
# Нью‑Йорк
dt_ny = datetime(2025, 7, 15, 12, 0, tzinfo=ZoneInfo("America/New_York"))
 
print(dt_msk)  # 2025-07-15 12:00:00+03:00
print(dt_ny)   # 2025-07-15 12:00:00-04:00

Конвертация между поясами:

python
dt_msk = datetime.now(ZoneInfo("Europe/Moscow"))
dt_ny = dt_msk.astimezone(ZoneInfo("America/New_York"))
 
print(dt_msk, "->", dt_ny)

Получение текущего времени в нужном поясе

python
from datetime import datetime
from zoneinfo import ZoneInfo
 
now_utc = datetime.now(ZoneInfo("UTC"))
now_msk = datetime.now(ZoneInfo("Europe/Moscow"))
 
print(now_utc)
print(now_msk)

Практический пример: лог с временной меткой и конвертацией

Допустим, нужно сохранять события в UTC, а показывать пользователю в его поясе.

python
from datetime import datetime
from zoneinfo import ZoneInfo
 
def записать_событие(сообщение, часовой_пояс_пользователя="Europe/Moscow"):
    # Храним в UTC
    dt_utc = datetime.now(ZoneInfo("UTC"))
 
    # Конвертируем для отображения
    tz_user = ZoneInfo(часовой_пояс_пользователя)
    dt_local = dt_utc.astimezone(tz_user)
 
    timestamp_str = dt_utc.strftime("%Y-%m-%dT%H:%M:%SZ")
    display_str = dt_local.strftime("%d.%m.%Y %H:%M")
 
    return {
        "сообщение": сообщение,
        "timestamp_utc": timestamp_str,
        "время_для_пользователя": display_str,
    }
 
event = записать_событие("Пользователь вошёл в систему")
print(event)

Такой подход позволяет хранить единое время (UTC) и корректно показывать его в любом часовом поясе.


Ещё один пример: валидация и нормализация даты из строки

Пользователь присылает дату в формате DD.MM.YYYY. Нужно превратить в datetime, проверить диапазон и вернуть в нужном формате:

python
from datetime import datetime
 
def нормализовать_дату(строка, формат_входа="%d.%m.%Y", формат_выхода="%Y-%m-%d"):
    try:
        dt = datetime.strptime(строка, формат_входа)
        # Пример проверки диапазона: не раньше 2000 года
        if dt.year < 2000:
            return None, "Год слишком ранний"
        return dt.strftime(формат_выхода), None
    except ValueError:
        return None, "Неверный формат даты"
 
res, err = нормализовать_дату("15.07.2025")
if err:
    print("Ошибка:", err)
else:
    print("Нормализованная дата:", res)


Частые ошибки и как их избежать

  • Смешивание naive и aware объектов. Нельзя напрямую сравнивать или вычитать datetime с часовым поясом и без него — будет TypeError. Всегда приводите к одному типу (лучше к aware).
  • Неверный шаблон в strptime. Если строка 15/07/2025, а шаблон %Y-%m-%d, будет ошибка. Проверяйте соответствие.
  • Хранение локальных дат вместо UTC. Для систем, где есть пользователи из разных часовых поясов, храните время в UTC, конвертируйте только на уровне отображения.
  • Использование datetime.utcnow(). Этот метод устарел. Лучше datetime.now(ZoneInfo("UTC")).

  • Для простых задач хватит datetime.now(), strftime/strptime, timedelta.
  • Для корректной работы с разными регионами используйте aware‑объекты: в новых версиях — zoneinfo, в старых — pytz.
  • Храните время в UTC, отображайте в локальном поясе пользователя.
  • Всегда проверяйте формат при разборе строк и избегайте смешивания naive и aware дат.

Добавить комментарий