okpython.net
Все для начинающих

Дата и время в Python

Введение

Довольно часто в программах на языке Python приходится манипулировать датой и временем, например, при выводе текущего времени в приложениях, вычислении временных промежутков, сохранении информации в базе данных, регистрации и обеспечении доступа пользователей к ресурсам и т. д. Для этих целей в Пайтоне предусмотрены модули стандартной библиотеки datetime, time и calendar, возможности которых мы и будем рассматривать в данном параграфе. Однако сперва давайте кратко рассмотрим несколько основных понятий, используемых в мировых стандартах, связанных с датой и временем.

Всемирное координированное время (от англ. Coordinated Universal Time, UTC) – это основной стандарт, по которому в мире регулируются часы и время. Перевод часов на зимнее и летнее время данным стандартом не предусмотрен.

Стандарт UTC возник из-за того, что среднее время по Гринвичу (GMT), т.е. среднее солнечное время нулевого меридиана, проходящего через прежнее место расположения Гринвичской королевской обсерватории около Лондона, неравномерно и связано с суточным вращением Земли, которое также неравномерно. В свою очередь, шкала UTC основана на равномерной шкале атомного времени и является более удобной для гражданского использования.

В настоящее время все часовые пояса определяются по их смещению относительно UTC, которое может быть нулевым, положительным или отрицательным. Так в Лондоне и некоторых других близлежащих городах смещение принимается равным нулю, т.е. они относятся к часовому поясу UTC+00:00. Минск и Москва, например, находятся в часовом поясе UTC+03:00, а Пекин в часовом поясе UTC+08:00. При этом переход на летнее время в этих городах не осуществляется, поэтому когда в Минске часы показывают 12 часов дня, в Пекине они показывают 17 часов вечера. В тоже время в Сальвадоре часы покажут 8 часов утра, ведь эта страна находится в часовом поясе UTC-03:00 (разница с Минском составляет 6 часов). Более того разница во времени может быть и не кратна целому количеству часов. Так в Тегеране часы покажут время 12 часов 30 минут, поскольку всемирное координированное время в данном районе установлено властями в UTC+03:30.

В некоторых странах несмотря на стандарт UTC используется переход на летнее время. В результате на летний период к стандартному времени прибавляется один час. Это делается для того, чтобы лучше использовать естественный свет и экономить электроэнергию. Однако летнее время применяется не во всех странах и, кроме того, не всегда совпадает по датам перевода часов. Поэтому, чтобы не запутаться во времени разных стран и регионов, рекомендуется использовать специальные карты часовых поясов или онлайн-сервисы, показывающие текущее время в любой точке мира.

Григорианский календарь – это система исчисления времени, которая основана на движении Земли вокруг Солнца. В этом календаре год состоит из 365 или 366 дней, если год является високосным. Високосные годы бывают каждые четыре года, исключая столетия, которые не делятся на 400 (например, 1600 и 2000 годы были високосными, а 1700, 1800 и 1900 годы високосными не были).

Григорианский календарь был введен в 1582 году папой римским Григорием XIII, чтобы исправить ошибку в юлианском календаре, который использовался до этого. Юлианский календарь был слишком длинным по сравнению с солнечным годом и поэтому нарушался порядок празднования Пасхи. В результате папа Григорий XIII решил отбросить 10 дней из календаря и ввести новые правила для високосных лет. Поэтому после 4 октября 1582 года сразу пошла дата 15 октября 1582 года.

Сейчас григорианский календарь является самым распространенным календарем в мире и используется для международной торговли, науки и общения. Его еще называют «новым стилем» по сравнению со «старым стилем» юлианского календаря.

Unix-время или временная метка Unix (от англ. Unix time) – это способ описания моментов во времени, который используется в Unix и других POSIX-совместимых операционных системах. Метка юникса показывает, сколько секунд прошло с полуночи 1 января 1970 года по всемирному координированному времени. Эта дата называется «эпохой Unix».

Метка Unix используется для хранения и обработки дат и времени почти во всех компьютерных системах, языках программирования и базах данных. Она может быть как положительной (время идет после эпохи юникса), так и отрицательной (время идет до эпохи юникса). Например, метка юникса 1627472400 соответствует дате и времени 28 июля 2021 года 12:00:00 по UTC. А вот отрицательная метка -31536000 (секунды отсчитываются в обратном направлении) соответствует 1 января 1969 года 00:00:00 по UTC.

Следует добавить, что в программах для хранения Unix-времени до некоторого момента использовались лишь 32-битные числа, которые давали возможность ссылаться на моменты времени от пятницы 13 декабря 1901 года 20:45:52 до вторника 19 января 2038 года 03:14:07 включительно. Теперь же все 64-битные операционные системы и подавляющая часть ПО стали использовать для работы 64-битные числа, что позволило расширить доступный для операций период времени до 292 млрд. лет.

Модуль datetime в Python

Модуль datetime стандартной библиотеки Пайтона является основным инструментом для управления датой и временем. В частности мы можем:

  • выводить текущие дату и время, а также их компоненты по отдельности;
  • форматировать их для более удобного восприятия пользователями;
  • сравнивать даты, а также находить их разницу и сумму,
  • выполнять ряд математических операций с временными интервалами.

Для реализации всех этих возможностей модуль предоставляет ряд классов и методов, подробно с которыми можно ознакомиться в разделе «datetime — Basic date and time types» стандартной библиотеки. Мы же пройдемся лишь по некоторым из них, чтобы получить более ясное представление о порядке работы с модулем.

Всего модуль datetime предлагает нам шесть основных классов и набор соответствующих им методов:

  • date – представляет собой дату на основе григорианского календаря, полностью игнорируя сведения о времени;
  • time – включает данные о времени, полностью игнорируя сведения о дате;
  • datetime – содержит информацию о времени и дате, основываясь на данных из григорианского календаря;
  • timedelta – предназначен для работы с интервалами дат и времени;
  • tzinfo – представляет различные сведения о часовом поясе;
  • timezone – предназначен для обработки времени по стандарту UTC.

Все перечисленные типы (классы) имеют следующие общие характеристики: объекты этих типов неизменяемы, хешируемы (а значит могут использоваться в качестве ключей словаря) и поддерживают сериализацию с помощью модуля pickle.

В общем случае для создания экземпляра класса datetime можно использовать конструктор datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0), в котором первые три параметра обязательны для передачи, а все последующие могут использоваться со значениями по умолчанию, включая именованный аргумент fold:

  • year – год в пределах datetime.MINYEAR ≤ year ≤ datetime.MAXYEAR, где константа datetime.MINYEAR равна 1, а datetime.MAXYEAR принимается равной 9999;
  • month – месяц в пределах 1 ≤ month ≤ 12;
  • day – день в пределах 1 ≤ day ≤ n_day, где n_day – количество дней в данном месяце заданного года;
  • hour=0 – часы в пределах 0 ≤ hour < 24;
  • minute=0 – минуты в пределах 0 ≤ minute < 60;
  • second=0 – секунды в пределах 0 ≤ second < 60;
  • microsecond=0 – микросекунды в пределах 0 ≤ microsecond < 1000 000;
  • tzinfo=None – экземпляр подкласса datetime.tzinfo (по умолчанию используется None);
  • fold=0 – флаг, сигнализирующий о летнем (0) или зимнем (1) времени.

После создания экземпляра класса все компоненты даты могут быть получены посредством соответствующих атрибутов, например, datetime_obj.year или datetime_obj.hour (см. пример №1).

Код Результат pythonCodes
# Импортируем класс datetime из одноименного модуля.
from datetime import datetime as dt
   
# 14.12.1503 - день рождения Нострадамуса.
# Создадим объект даты и времени для этого события.
date_and_time = dt(1503, 12, 14, 11, 1, 25)

# Получаем компоненты по отдельности.
year = date_and_time.year
month = date_and_time.month 
day = date_and_time.day 
hour = date_and_time.hour
minute = date_and_time.minute
second = date_and_time.second

# Выводим строковое представление объекта.
# Дата и время: 1503-12-14 11:01:25.
print('Дата и время:', date_and_time)
# Форматируем по-своему и выводим. 
d = '{}.{}.{}'.format(day, month, year)
# Дата: 14.12.1503.
print('Дата:', d)
t = '{}:0{}:{}'.format(hour, minute, second)
# Время: 11:01:25.
print('Время:', t)
Дата и время: 1503-12-14 11:01:25
Дата: 14.12.1503
Время: 11:01:25




















		
			

Пример №1. Использование модуля datetime (часть 1).

Объекты класса datetime могут быть созданы и при помощи соответствующих методов класса:

  • datetime.datetime.today() – возвращает текущую локальную дату и время (tzinfo=None);
  • datetime.datetime.now(tz=None) – возвращает текущую локальную дату и время;
  • datetime.datetime.utcnow() – возвращает текущую дату и время UTC (tzinfo=None);
  • datetime.datetime.fromtimestamp(timestamp, tz=None) – возвращает локальную дату и время, соответствующие метке времени POSIX time.time();
  • datetime.datetime.utcfromtimestamp(timestamp) – возвращает дату и время UTC, соответствующие метке времени POSIX (tzinfo=None);
  • datetime.datetime.combine(datetime.date, datetime.time, tzinfo=self.tzinfo) – возвращает новый объект datetime.datetime(), компоненты даты date которого соответствуют переданному объекту datetime.date, а компоненты времени time – переданному объекту datetime.time;
  • datetime.datetime.fromisoformat(date_string) – возвращает объект даты и времени datetime.datetime(), соответствующий строке date_string в любом допустимом формате ISO 8601, но со следующими исключениями:
    • смещение часового пояса может составлять доли секунды,
    • разделитель T может быть заменен любым символом Юникода,
    • отсутствует поддержка порядковых дат,
    • также не поддерживаются дробные часы и минуты;
  • datetime.datetime.fromisocalendar(year, week, day) – возвращает объект даты и времени, соответствующий календарной дате формата ISO 8601, указанной в атрибутах year, week, day (остальные компоненты datetime заполняются их обычными значениями по умолчанию);
Использование некоторых из этих методов класса показано в примере №2.

Код Результат pythonCodes
# Импортируем модуль time.
import time as tm
# Импортируем класс datetime из модуля datetime.
from datetime import datetime as dt
# Импортируем классы date, time, timezone.
from datetime import date, time, timezone  

# 2023-08-01 10:08:33.646700.
print(dt.today())
# 2023-08-01 10:08:33.646699.
print(dt.now(), end='\n\n')

# 2023-08-01 07:08:33.646699.
print(dt.utcnow())
# Рекомендуемый способ создания объекта c текущим временем 
# в UTC без смещения: 2023-08-01 07:08:33.646699+00:00.
print(dt.now(timezone.utc), end='\n\n')

# 2023-08-01 10:08:33.646699.
print(dt.fromtimestamp(tm.time()))
# 2023-08-01 07:08:33.646699+00:00.
print(dt.fromtimestamp(tm.time(), timezone.utc), end='\n\n')

# 1995-05-09 09:13:20 (800 млн. сек. с начала эпохи).
print(dt.fromtimestamp(800000000))
# 1998-07-09 16:00:00+00:00 (900 млн. сек. с начала эпохи).
print(dt.fromtimestamp(900000000, timezone.utc), end='\n\n')

# 2023-08-01 15:25:00.
print(dt.combine(date.today(), time(15, 25)), end='\n\n')

# Получаем экземпляры из строк в формате ISO 8601.
# 2023-08-01 00:00:00.
print(dt.fromisoformat('2023-08-01'))
# 2023-08-01 00:00:00.
print(dt.fromisoformat('20230801'))
# 2023-08-01 00:15:25+00:00.
print(dt.fromisoformat('2023-08-01T00:15:25Z'))
2023-08-01 10:08:33.646699
2023-08-01 10:08:33.646699

2023-08-01 07:08:33.646699
2023-08-01 07:08:33.646699+00:00

2023-08-01 10:08:33.646699
2023-08-01 07:08:33.646699+00:00

1995-05-09 09:13:20
1998-07-09 16:00:00+00:00

2023-08-01 15:25:00

2023-08-01 00:00:00
2023-08-01 00:00:00
2023-08-01 00:15:25+00:00



















		
			

Пример №2. Использование модуля datetime (часть 2).

Опять же, после создания экземпляра даты и времени доступ к его компонентам можно получить посредством соответствующих атрибутов. Кроме того, становится доступен и ряд методов для работы с данными объекта (см. пример №3):

  • date() – возвращает объект даты с теми же значениями атрибутов year, month и day;
  • time() – возвращает объект времени с теми же значениями атрибутов hour, minute, second, microsecond и fold (tzinfo устанавливается в None);
  • timetz() – возвращает объект времени с теми же значениями атрибутов hour, minute, second, microsecond, fold и tzinfo;
  • replace(year=self.year, month=self.month, day=self.day, hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, tzinfo=self.tzinfo, *, fold=0) – возвращает новый объект datetime.datetime() с теми же атрибутами, за исключением тех, для которых были переданы новые значения;
  • timetuple() – возвращает именованный кортеж структуры времени time.struct_time, в котором содержатся компоненты даты и времени, которые доступны по именам tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst;
  • timestamp() – возвращает метку времени POSIX (число с плавающей точкой, аналогичное тому, которое возвращает time.time()), соответствующую экземпляру datetime.datetime();
  • ctime() – возвращает строку, представляющую дату и время;
  • strftime(format) – возвращает строку, представляющую дату и время, форматируемую согласно строковому параметру format (порядок работы с методом см. в справочнике).

Код Результат pythonCodes
# Импортируем класс datetime из модуля.
from datetime import datetime as dt
 
# Получаем экземпляр текущего времени.
cur_dt = dt.now()
# Выводим строковые представления объектов.
# Дата и время: 2023-09-03 16:53:37.515892.
print('Дата и время:', cur_dt)
# Дата: 2023-09-03.
print('Дата:', cur_dt.date())
# Время: 16:53:37.515892.
print('Время:', cur_dt.time(), end='\n\n')

# Опять же, получаем компоненты по отдельности, 
# использовав атрибуты полученного экземпляра.
year = cur_dt.year
month = cur_dt.month 
day = cur_dt.day 
hour = cur_dt.hour
minute = cur_dt.minute
second = cur_dt.second
# Форматируем по-своему и выводим. 
d_1 = '0{}.0{}.{}'.format(day, month, year)
# Дата: 03.09.2023.
print('Дата:', d_1)
t_1 = '{}:{}:{}'.format(hour, minute, second)
# Время: 16:53:37. 
print('Время:', t_1, end='\n\n')

# Также можно получить все компоненты в виде именованного кортежа:
# time.struct_time(tm_year=2023, tm_mon=9, tm_mday=3, tm_hour=16, 
# tm_min=53, tm_sec=37, tm_wday=6, tm_yday=246, tm_isdst=-1).
tm_tpl = cur_dt.timetuple()
# Форматируем по-своему и выводим. 
d_2 = '0{}.0{}.{}'.format(tm_tpl.tm_mday, tm_tpl.tm_mon, tm_tpl.tm_year)
# Дата: 03.09.2023.
print('Дата:', d_2)
t_2 = '{}:{}:{}'.format(tm_tpl.tm_hour, tm_tpl.tm_min, tm_tpl.tm_sec)
# Время: 16:53:37.
print('Время:', t_2, end='\n\n')

# Прошло секунд с начала Эпохи Unix: 1693749217.515892.
# Почти 1.7 млрд. секунд! 
print(cur_dt.timestamp())
# Sun Sep  3 16:53:37 2023 (в виде отформатированной строки).
print(cur_dt.ctime(), end='\n\n')

# 16 часов 53 минут 03.09.2023 года.
print(cur_dt.strftime('%H часов %M минут %d.%m.%Y года'))
# 03.09.2023.
print(cur_dt.strftime('%d.%m.%Y'), end='\n\n')

# Изменили на 2020-07-03 10:53:37.515892.
print(cur_dt.replace(year=2020, month=7, hour=10))
Дата и время: 2023-09-03 16:53:37.515892
Дата: 2023-09-03
Время: 16:53:37.515892

Дата: 03.09.2023
Время: 16:53:37

Дата: 03.09.2023
Время: 16:53:37

1693749217.515892
Sun Sep  3 16:53:37 2023

16 часов 53 минут 03.09.2023 года
03.09.2023

2020-07-03 10:53:37.515892



































		
			

Пример №3. Использование модуля datetime (часть 3).

Здесь мы перечислили далеко не все методы, доступные экземплярам класса datetime.datetime, поэтому обязательно посетите справочник и хотя бы бегло ознакомьтесь с документацией. Это касается и классов datetime.date (работа только с датами) и datetime.time (работа только со временем), поскольку принцип работы с ними не сильно отличается от порядка использования более общего класса datetime.datetime.

Стоит добавить, что для экземпляров классов datetime.datetime и datetime.date дополнительно предусмотрена возможность осуществления операций сложения, вычитания и сравнения. При чем в операциях сложения и вычитания могут участвовать еще и экземпляры класса datetime.timedelta, представляющего временные интервалы (см. пример №4).

Код Результат pythonCodes
# Импортируем класс datetime из модуля datetime.
from datetime import datetime as dt
# Импортируем класс timedelta из модуля datetime.
from datetime import timedelta as tdl
 
# Создаем экземпляр даты для нового 2024 года.
new_year_dt = dt(2024, 1, 1, 0, 0, 0)
# Получаем экземпляр текущего времени.
cur_dt = dt.today()

# Узнаем дату через 17 дней и 3 недели.
next_dt = cur_dt + tdl(days=17, weeks=3)
# 2023-10-12 12:02:23.651890.
print(next_dt)

# Наступит ли уже новый год? (False).
print(next_dt > new_year_dt)    

# Узнаем, сколько времени осталось до НГ.
# 118 days, 11:57:36.348110.
print(new_year_dt - cur_dt)

# Для объектов класса time операции с интервалами не поддерживаются.
# unsupported operand type(s) for +: 'datetime.time' and 'datetime.timedelta'
# print(cur_dt.time() + tdl(hours=3))
2023-10-12 12:02:23.651890
False
118 days, 11:57:36.348110




















		
			

Пример №4. Использование модуля datetime (часть 4).

В нашем примере экземпляр класса timedelta был создан с помощью конструктора datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0), в котором все параметры необязательны для передачи, могут быть как положительными, так и отрицательными целыми или вещественными числами и по умолчанию принимают нулевые значения. При этом как есть хранятся только дни, секунды и микросекунды, а все остальные аргументы преобразуются к этим трем:

  • миллисекунда конвертируется в 1000 микросекунд,
  • минута конвертируется в 60 секунд,
  • час конвертируется в 3600 секунд,
  • неделя конвертируется в 7 дней.

Далее дни, секунды и микросекунды нормализуются таким образом, чтобы представление интервала было однозначным, а нормализованные значения попадали в следующие диапазоны:

  • 0 <= microseconds < 1000000,
  • 0 <= seconds < 3600*24 (количество секунд в одном дне),
  • -999999999 <= days <= 999999999.

Для наглядности несколько случаев создания объектов класса timedelta представлено в примере №5.

Код Результат pythonCodes
# Импортируем класс timedelta из модуля datetime.
from datetime import timedelta as tdl

# Создаем экземпляр интервала времени.
dlt_1 = tdl(
days=50,
seconds=27,
microseconds=15,
milliseconds=18000,
minutes=12,
hours=8,
weeks=3)

# Смотрим, в каком виде все хранится.
# datetime.timedelta(days=71, seconds=29565, microseconds=15).
print(repr(dlt_1))    
# Выводим привычное строковое представление.
# 71 days, 8:12:45.000015.
print(dlt_1, end='\n\n') 

# Сумма дробных остатков микросекунд в результате округляется
# до ближайшего целого. Поэтому 1014.6 округляется до 1015.  
dlt_2 = tdl(milliseconds=1.0045, microseconds=10.1) 
# datetime.timedelta(microseconds=1015).
print(repr(dlt_2))    
# 0.5 округляется вниз, поэтому получим 10.
dlt_3 = tdl(microseconds=10.5) 
# datetime.timedelta(microseconds=10).
print(repr(dlt_3), end='\n\n')       

# Нормализация отрицательных значений весьма неожиданна.
dlt_4 = tdl(milliseconds=-10) 
# datetime.timedelta(days=-1, seconds=86399, microseconds=990000). 
print(repr(dlt_4))    
# -10.5 округляется вниз до -10 (а вот -10.51 уже до -11).
dlt_5 = tdl(microseconds=-10.5) 
# datetime.timedelta(days=-1, seconds=86399, microseconds=999990).
print(repr(dlt_5))
datetime.timedelta(days=71, seconds=29565, microseconds=15)
71 days, 8:12:45.000015

datetime.timedelta(microseconds=1015)
datetime.timedelta(microseconds=10)

datetime.timedelta(days=-1, seconds=86399, microseconds=990000)
datetime.timedelta(days=-1, seconds=86399, microseconds=999990)




























		
			

Пример №5. Использование модуля datetime (часть 5).

Как видим, в результате нормализации на внутреннем хранении остаются только дни, секунды и микросекунды. При этом все остатки дробных микросекунд суммируются, а затем округляются до ближайшего целого за исключением половины микросекунды, которая округляется вниз до целого. Например, 1.23 и 1.5 микросекунды округлятся до одной микросекунды, 1.51 микросекунды округлится до двух микросекунд, -1.23 микросекунды округлится до -1 микросекунды, а -1.51 и -1.5 микросекунды округлятся до -2 микросекунд. Также следует помнить, что нормализованное значение дней не должно выходить за пределы допустимого диапазона, иначе будет вызвано исключение OverflowError.

После создания экземпляров класса timedelta над ними можно выполнять целый ряд математических операций: сложение, вычитание, умножение, деление и т.д. (см. пример №6, а также полную таблицу доступных операций с пояснениями в справочнике стандартной библиотеки Пайтона).

Код Результат pythonCodes
# Импортируем класс timedelta из модуля datetime.
from datetime import timedelta as tdl

# Создаем интервал невисокосного года.
year = tdl(days=365)
# Три невисокосных года получаем простым умножением.
three_years = 3*year    
# datetime.timedelta(days=1095).
print(repr(three_years))     

# Получаем високосный год.
one_day = tdl(days=1)
leap_year = year + one_day    
# datetime.timedelta(days=366).
print(repr(leap_year), end='\n\n')     

# Выведет везде True.
# Можно сравнивать интервалы.
print(three_years > year)     
# Обычное деление.
print(three_years/3 == year)    
# t_1//t_2 -> int (целочисленное деление).
print(three_years//(2*year) == 1)    
# t_1//int -> t_2 (как обычное деление).
print(three_years//2 == three_years/2)    
# t_1%t_2 -> t_3 (остаток от деления).
print(three_years%(2*year) == year, end='\n\n')

# Имеется у экземпляров класса и метод, который 
# выводит общее кол-во секунд: 86400.0.
print(one_day.total_seconds())
datetime.timedelta(days=1095)
datetime.timedelta(days=366)

True
True
True
True
True

86400.0



















		
			

Пример №6. Использование модуля datetime (часть 6).

Следует заметить, что стандартный модуль datetime не поддерживает автоматическое определение и конвертацию часовых поясов. Для этого нужно использовать дополнительные библиотеки, такие как pytz или dateutil (см. пример №7).

Pytz - это библиотека, которая предоставляет базу данных часовых поясов IANA, содержащую исторические и актуальные данные о смещениях и правилах перехода на летнее время для разных регионов мира. Pytz позволяет создавать объекты tzinfo, которые являются абстрактными представлениями часовых поясов, и присоединять их к объектам datetime для указания их временной зоны.

Dateutil - более мощная библиотека, которая предоставляет различные утилиты для работы с датой и временем. Dateutil также поддерживает базу данных часовых поясов IANA и позволяет создавать объекты tzinfo с помощью функции gettz.

Код Результат pythonCodes
# Импортируем необходимые модули.
import datetime
import pytz
import dateutil.tz

# Создаем объект datetime без указания часового пояса.
dt = datetime.datetime(2022, 12, 31, 23, 59, 59)
# 2022-12-31 23:59:59.
print(dt) 

# Создаем объект tzinfo для часового пояса Минска.
minsk_tz = dateutil.tz.gettz("Europe/Minsk")
# Создаем объект tzinfo для часового пояса Нью-Йорка.
new_york_tz = dateutil.tz.gettz("America/New_York")

# Задаем объекту datetime часовой пояс Минска.
dt_minsk_tz = dt.astimezone(minsk_tz)
# 2020-12-31 23:59:59+03:00.
print(dt_minsk_tz)     

# Конвертируем объект datetime из одного часового пояса в другой.
dt_new_york = dt.astimezone(new_york_tz)
# 2020-12-31 15:59:59-05:00 (время перевелось автоматически).
print(dt_new_york, end='\n\n') 

# Тоже самое с помощью pytz.

# Создаем объект datetime без указания часового пояса.
dt = datetime.datetime(2022, 12, 31, 23, 59, 59)
# 2022-12-31 23:59:59.
print(dt) 
    
# Создаем объект tzinfo для часового пояса Минска.
minsk_tz = pytz.timezone("Europe/Minsk")
# Вначале обязательно переходим на UTC (доп. действие).
dt.replace(tzinfo=pytz.utc)
# Задаем объекту datetime часовой пояс Минска.
dt_minsk = dt.astimezone(minsk_tz)
# 2020-12-31 23:59:59+03:00.
print(dt_minsk) 

# Создаем объект tzinfo для часового пояса Нью-Йорка.
new_york_tz = pytz.timezone("America/New_York")
# Конвертируем объект datetime из одного часового пояса в другой.
dt_new_york = dt_minsk.astimezone(new_york_tz)
# 2020-12-31 15:59:59-05:00 (время перевелось автоматически).
print(dt_new_york, end='\n\n') 

# Выводим список актуальных названий зон базы IANA.
print(pytz.common_timezones)
2022-12-31 23:59:59
2022-12-31 23:59:59+03:00
2022-12-31 15:59:59-05:00

2022-12-31 23:59:59
2022-12-31 23:59:59+03:00
2022-12-31 15:59:59-05:00

['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', 
'Africa/Algiers', 'Africa/Asmara', 'Africa/Bamako', 
'Africa/Bangui', 'Africa/Banjul', 'Africa/Bissau', 

...

'Europe/Berlin', 'Europe/Bratislava', 'Europe/Brussels', 
'Europe/Bucharest', 'Europe/Budapest', 'Europe/Busingen', 
'Europe/Chisinau', 'Europe/Copenhagen', 'Europe/Dublin', 
'Europe/Gibraltar', 'Europe/Guernsey', 'Europe/Helsinki', 
'Europe/Isle_of_Man', 'Europe/Istanbul', 'Europe/Jersey', 
'Europe/Kaliningrad', 'Europe/Kirov', 'Europe/Kyiv', 
'Europe/Lisbon', 'Europe/Ljubljana', 'Europe/London', 
'Europe/Luxembourg', 'Europe/Madrid', 'Europe/Malta', 
'Europe/Mariehamn', 'Europe/Minsk', 'Europe/Monaco', 
'Europe/Moscow', 'Europe/Oslo', 'Europe/Paris', 

...

'Pacific/Wake', 'Pacific/Wallis', 'US/Alaska', 
'US/Arizona', 'US/Central', 'US/Eastern', 'US/Hawaii', 
'US/Mountain', 'US/Pacific', 'UTC']


















		
			

Пример №7. Использование библиотек pytz и dateutile.

Поскольку библиотеки pytz и dateutil в состав стандартной библиотеки Питона не входят, их нужно сперва в окружение установить, использовав для этого команды «pip install pytz» и «pip install python-dateutil».

Модуль time в Python

Еще одним модулем стандартной библиотеки, позволяющем работать с датой и временем, является более старый модуль time. У него меньше методов для манипулирования датой и временем в удобочитаемом для человека формате, но зато он предоставляет возможности для работы с системным временем и некоторые другие возможности, связанные с временем выполнения программ (см. пример №8).

Код Результат pythonCodes
# Импортируем модуль. 
import time

# Возвращает кол-во секунд, прошедших с начала эпохи.
t_1 = time.time()
# Вывело 1707917834.5482302.
print(t_1)    

# Текущие время и дата в удобочитаемом формате.
t_2 = time.ctime()
# Вывело Wed Feb 14 16:37:14 2024. 
print(t_2)  

# Можно преобразовывать и секунды.
t_3 = time.ctime(700000000)
# Вывело Sat Mar  7 23:26:40 1992. 
print(t_3, end='\n\n') 

# Приостанавливаем работу скрипта на 2 сек.
time.sleep(2) 
    
# Возвращает экземпляр класса time.struct_time
# в формате UTC. Если секунды не передаются, 
# используется текущее время по UTC.
tpl_1 = time.gmtime()
# Вывело time.struct_time(tm_year=2024, tm_mon=2, 
# tm_mday=14, tm_hour=13, tm_min=37, tm_sec=16, 
# tm_wday=2, tm_yday=45, tm_isdst=0). 
print(tpl_1)
# Вывело 13:37. 
print(tpl_1.tm_hour, ':', tpl_1.tm_min, sep='')    

# Тоже что и gmtime(), но с локальным временем.
tpl_2 = time.localtime()
# Вывело time.struct_time(tm_year=2024, tm_mon=2, 
# tm_mday=14, tm_hour=16, tm_min=37, tm_sec=16, 
# tm_wday=2, tm_yday=45, tm_isdst=0). 
print(tpl_2)

# Преобразует struct_time в кол-во секунд с 
# начала эпохи (процесс, обратный localtime()).
t_4 = time.mktime(tpl_2)
# Вывело 1707917836.0. 
print(t_4) 

# Преобразует struct_time в удобочитаемый формат. 
t_5 = time.asctime(tpl_2)
# Вывело Wed Feb 14 16:37:16 2024. 
print(t_5)     

# Преобразует struct_time в нужный формат,
# см. выше datetime.strftime(format).
t_6 = time.strftime('%d.%m.%Y', tpl_2)
# Вывело 14.02.2024. 
print(t_6)     

# Преобр-ние строки со временем в struct_time.
tpl_3 = time.strptime(t_6, '%d.%m.%Y')
# Вывело time.struct_time(tm_year=2024, tm_mon=2, 
# tm_mday=14, tm_hour=0, tm_min=0, tm_sec=0, 
# tm_wday=2, tm_yday=45, tm_isdst=-1). 
print(tpl_3)
1707917834.5482302
Wed Feb 14 16:37:14 2024
Sat Mar  7 23:26:40 1992

time.struct_time(tm_year=2024, tm_mon=2, tm_mday=14, 
tm_hour=13, tm_min=37, tm_sec=16, tm_wday=2, tm_yday=45, tm_isdst=0)
13:37
time.struct_time(tm_year=2024, tm_mon=2, tm_mday=14, tm_hour=16, 
tm_min=37, tm_sec=16, tm_wday=2, tm_yday=45, tm_isdst=0)
1707917836.0
Wed Feb 14 16:37:16 2024
14.02.2024
time.struct_time(tm_year=2024, tm_mon=2, tm_mday=14, tm_hour=0, 
tm_min=0, tm_sec=0, tm_wday=2, tm_yday=45, tm_isdst=-1)














































		
			

Пример №8. Использование модуля time.

Как видим, все возможности модуля time для работы с обычными датой и временем представлены и в более специализированном для этих целей модуле datetime.

Модуль calendar в Python

Модуль calendar предоставляет дополнительные возможности для работы с календарем. С его помощью можно выводить календари в разных форматах, таких как текст или HTML, а также выполнять различные расчеты, связанные с датами, месяцами и годами. При этом функции и классы, определенные в этом модуле, используют идеализированный календарь, представляющий собой нынешний григорианский календарь, расширенный бесконечно в обоих направлениях. В таком календаре нулевые и отрицательные годы интерпретируются согласно стандарту ISO 8601, где год 0 приравнен к 1-му году до н.э., год -1 приравнен ко 2-му году до н.э. и т.д.

Основным классом, который используется в модуле calendar, является calendar.Calendar. Этот класс создает экземпляр календаря, который предоставляет несколько методов для подготовки данных календаря для форматирования. Сам класс не занимается форматированием, это задача классов calendar.TextCalendar, calendar.HTMLCalendar, а также их подклассов calendar.LocaleTextCalendar и calendar.LocaleHTMLCalendar, которые позволяют создавать календари с названиями на родном языке.

Конструктор класса calendar.Calendar(firstweekday=0) принимает параметр firstweekday в виде целого числа, определяющего первый день недели. По умолчанию это 0, что соответствует понедельнику (соответственно для воскресенья используется индекс 6). Перечислим основные методы экземпляров класса.

  • iterweekdays() – возвращает итератор для номеров дней недели, которые будут использоваться для одной недели. Первое значение из итератора будет совпадать со значением свойства firstweekday.
  • itermonthdates(year, month) – возвращает итератор для месяца month (112) в году year. Этот итератор будет возвращать все даты (как объекты datetime.date) для месяца и все даты до начала месяца или после конца месяца, которые необходимы для получения полной недели.
  • itermonthdays(year, month) – возвращает итератор для месяца month в году year, аналогичный itermonthdates(), но не ограниченный диапазоном datetime.date. Даты возвращаются просто как номера дней месяца. Для дат вне указанного месяца номер дня равен 0.
  • itermonthdays2(year, month) – возвращает итератор для месяца month в году year, аналогичный itermonthdates(), но не ограниченный диапазоном datetime.date. Даты возвращаются в виде кортежей, состоящих из номера дня месяца и номера дня недели.
  • itermonthdays3(year, month) – возвращает итератор для месяца month в году year, аналогичный itermonthdates(), но не ограниченный диапазоном datetime.date. Даты возвращаются в виде кортежей, состоящих из номера года, номера месяца и номера дня месяца.
  • itermonthdays4(year, month) – итератор для месяца month в году year, аналогичный itermonthdates(), но не ограниченный диапазоном datetime.date. Даты возвращаются в виде кортежей, состоящих из номера года, номера месяца, номера дня месяца и номера дня недели.
  • monthdatescalendar(year, month) – список недель в месяце month года year в виде полных недель. Каждая неделя представляет собой список объектов datetime.date.
  • monthdays2calendar(year, month) – список недель в месяце month года year в виде полных недель. Каждая неделя представляет собой список кортежей из номеров дней месяца и дней недели.
  • monthdayscalendar(year, month) – список недель в месяце month года year в виде полных недель. Каждая неделя представляет собой список номеров дней месяца.
  • yeardatescalendar(year, width=3) – список месяцев в году year в виде матрицы недель. Каждый месяц представляет собой список недель, а каждая неделя - список объектов datetime.date. Параметр width определяет количество месяцев в одной строке.
  • yeardays2calendar(year, width=3) – список месяцев в году year в виде матрицы недель. Каждый месяц представляет собой список недель, а каждая неделя - список кортежей из номеров дней месяца и дней недели. Параметр width определяет количество месяцев в одной строке.
  • yeardayscalendar(year, width=3) – список месяцев в году year в виде матрицы недель. Каждый месяц представляет собой список недель, а каждая неделя - список номеров дней месяца. Параметр width определяет количество месяцев в одной строке.
Рассмотрим использование методов на примере №9.

Код Результат pythonCodes
# Импортируем модуль.
import calendar

# Создаем экземпляр класса календаря.
cl = calendar.Calendar()

# Преобразуем в кортеж для наглядности.
# Вывело (0, 1, 2, 3, 4, 5, 6).
print(tuple(cl.iterweekdays()), end='\n\n')

# Выводим даты для февраля 2024 года.
for date in cl.itermonthdates(2024, 2):
    print(date)  

print()
# Или просто номера дней февраля 2024 года.
# (0, 0, 0, 1, 2, ..., 29, 0, 0, 0).
print(tuple(cl.itermonthdays(2024, 2)), end='\n\n')    

# Номер_дня/день_недели для февраля 2024 года.
for day, weekday in cl.itermonthdays2(2024, 2):
    print(day, weekday)

print()
# Выводим список недель для февраля 2024 года.
for week in cl.monthdayscalendar(2024, 2):
    print(week)

print()
# Получаем матрицу месяцев для 2024 года и 
# выводим только список недель для февраля.
for week in cl.yeardayscalendar(2024)[0][1]:
    print(week)
(0, 1, 2, 3, 4, 5, 6)

2024-01-29
2024-01-30
2024-01-31
2024-02-01
2024-02-02
...
2024-02-29
2024-03-01
2024-03-02
2024-03-03

(0, 0, 0, 1, 2, ..., 28, 29, 0, 0, 0)

0 0
0 1
0 2
1 3
...
28 2
29 3
0 4
0 5
0 6

[0, 0, 0, 1, 2, 3, 4]
...
[26, 27, 28, 29, 0, 0, 0]

[0, 0, 0, 1, 2, 3, 4]
...
[26, 27, 28, 29, 0, 0, 0]

Пример №9. Использование модуля calendar (часть 1).

Класс calendar.TextCalendar используется для создания обычных текстовых календарей с возможностью предварительного форматирования за счет небольшого количества имеющихся у него методов экземпляров класса.

  • formatmonth(theyear, themonth, w=0, l=0) – возвращает календарь на месяц themonth (от 1 до 12) в году theyear в виде многострочной строки. Если задан параметр w, он определяет ширину столбцов с датами. Параметр l задает количество строк, используемых для каждой недели.
  • formatyear(theyear, w=2, l=1, c=6, m=3) – возвращает календарь на год theyear в виде многострочной строки. Параметры w, l и c определяют ширину столбцов с датами, количество строк между месяцами и количество пробелов между месяцами соответственно. Параметр m определяет количество месяцев в одной строке.
  • prmonth(theyear, themonth, w=0, l=0) – выводит календарь на месяц themonth в году theyear на стандартный поток вывода. Параметр w и l аналогичны методу formatmonth().
  • pryear(theyear, w=2, l=1, c=6, m=3) – выводит календарь на год theyear на стандартный поток вывода. Параметры w, l, c и m аналогичны методу formatyear().
Рассмотрим использование методов на примере №10.

Код Результат pythonCodes
# Импортируем модуль.
import calendar

# Создаем экземпляр текстового календаря.
text_cal = calendar.TextCalendar()

# Выводим текстовый календарь на февраль 2024 года.
print(text_cal.formatmonth(2024, 2))
# Еще раз, но со своим форматированием.
cl = text_cal.formatmonth(2024, 2, 3, 2)
print(cl, end='\n\n')
# И заодно сохраним в файле для распечатки.    
with open('feb.txt', 'w') as f: f.write(cl)
    
# Выводим текстовый календарь на весь 2024 год.
print(text_cal.formatyear(2024))    
# Еще раз, но со своим форматированием.
print(text_cal.formatyear(2024, 3, 2, 5, 3))
        February 2024
 Mo Tu We Th  Fr Sa Su
                      1   2   3   4
   5    6    7    8   9 10 11
 12  13 14  15 16 17 18
 19  20 21  22 23 24 25
 26  27 28  29

                February 2024

Mon Tue Wed Thu Fri Sat Sun

                             1    2    3     4

     5     6       7     8    9  10    11

   12   13    14   15  16  17    18
 ...

Пример №10. Использование модуля calendar (часть 2).

Имеется в модуле и возможность использования в календарях названий на родном языке. Для этого служит подкласс calendar.LocaleTextCalendar(firstweekday=0, locale=None), конструктор которого содержит параметр locale для установки требуемого значения локали (см. пример №11).

Код Результат pythonCodes
# Импортируем модули.
import calendar, locale

# Создаем экземпляр текстового календаря.
ru_cal = calendar.LocaleTextCalendar(locale='ru_RU')
# Выводим текстовый календарь на февраль 2024 года.
print(ru_cal.formatmonth(2024, 2))

# Получаем мою текущую локаль ('Russian_Belarus').
lc = locale.getlocale()[0]

# Создаем экземпляр текстового календаря.
ru_cal = calendar.LocaleTextCalendar(locale=lc)
# Выводим текстовый календарь на февраль 2024 года.
print(ru_cal.formatmonth(2024, 2))
        Февраль 2024
 Пн Вт Ср Чт  Пт Сб Вс
                      1   2   3   4
   5    6    7    8   9 10 11
 12  13 14  15 16 17 18
 19  20 21  22 23 24 25
 26  27 28  29

        февраль 2024
 пн вт ср чт  пт сб вс
                      1   2   3   4
   5    6    7    8   9 10 11
 12  13 14  15 16 17 18
 19  20 21  22 23 24 25
 26  27 28  29

Пример №11. Использование модуля calendar (часть 3).

Помимо возможности создания обычных текстовых календарей модуль позволяет создавать и календари в формате HTML. Для этого предназначен класс calendar.HTMLCalendar( firstweekday=0) и его подкласс calendar.LocaleHTMLCalendar( firstweekday=0, locale=None), позволяющий использовать в календаре названия на родном языке. Ознакомиться с описанием этих классов можно в справочнике стандартной библиотеки. Здесь же нам осталось лишь перечислить основные полезные методы и атрибуты модуля. Начнем с методов.

  • calendar.setfirstweekday(weekday) – устанавливает переданный день в качестве начала каждой недели. Передавать можно числа либо значения: 0 или MONDAY, 1 или TUESDAY, 2 или WEDNESDAY, 3 или THURSDAY, 4 или FRIDAY, 5 или SATURDAY и 6 или SUNDAY.
  • calendar.firstweekday() – возвращает текущую настройку для дня, используемого в качестве начала каждой недели.
  • calendar.isleap(year) – возвращает True если year високосный год, иначе False.
  • calendar.leapdays(y1, y2) – возвращает количество високосных лет в диапазоне от y1 до y2. Функция работает для диапазонов, охватывающих столетие изменения.
  • calendar.weekday(year, month, day) – возвращает индекс дня недели (0 соответствует понедельнику) для year начиная с 1970 года, month от 1 до 12), day от 1 до 31.
  • calendar.weekheader(n) – возвращает заголовок, содержащий сокращенные имена дней недели. Здесь n задает ширину в символах для одного дня недели.
  • calendar.monthrange(year, month) – возвращает день недели первого дня месяца и количество дней в месяце для указанного year и month.
  • calendar.monthcalendar(year, month) – возвращает матрицу, представляющую календарь на месяц. Каждая строка представляет неделю, а дни вне месяца представлены нулями. Кроме того, каждая неделя начинается с понедельника, если это не установлено setfirstweekday().
  • calendar.month(theyear, themonth, w=0, l=0) – возвращает календарь месяца в многострочной строке, используя formatmonth() класса TextCalendar.
  • calendar.prmonth(theyear, themonth, w=0, l=0) – печатает календарь месяца, а не возвращает его как month().
  • calendar.calendar(year, w=2, l=1, c=6, m=3) – возвращает календарь с тремя колонками в течение всего года в виде многострочной строки, используя formatyear() класса TextCalendar.
  • calendar.prcal(year, w=0, l=0, c=6, m=3) – печатает календарь на весь год, а не возвращает его как calendar().
  • calendar.timegm(tuple) – принимает именованный кортеж времени (такой как возвращается методом time.gmtime()) и возвращает соответствующее значение временной метки Unix (по сути совершая обратную операцию).
Рассмотрим использование методов на примере №12.

Код Результат pythonCodes
# Импортируем модули.
import calendar

# Делаем четверг первым днем недели.
calendar.setfirstweekday(3)
# Проверяем настройку.
print(calendar.firstweekday())
# Возвращаем настройку.
calendar.setfirstweekday(0)    

# True, т.к. год високосный.
print(calendar.isleap(2024))    

# Вернет индекс 1, т.е. вторник.
print(calendar.weekday(2024, 4, 2))     

# Вернет M T W T F S S.
print(calendar.weekheader(1))  
# Вернет Mo Tu We Th Fr Sa Su.
print(calendar.weekheader(2))     

# 1-я неделя февраля [0, 0, 0, 1, 2, 3, 4].
print(calendar.monthcalendar(2024, 2)[0]) 
3
True
1
M T W T F S S
Mo Tu We Th Fr Sa Su
[0, 0, 0, 1, 2, 3, 4]
















 

Пример №12. Использование модуля calendar (часть 4).

Теперь перечислим некоторые полезные атрибуты данных модуля и покажем их работу в исходном коде на примере №13.

  • calendar.day_name – объект (массив), представляющий дни недели в текущей локали с доступом по индексу от 0 (понедельник) до 6 (воскресенье).
  • calendar.day_abbr – объект (массив), представляющий сокращенные дни недели в текущей локали с доступом по индексу от 0 (понедельник) до 6 (воскресенье).
  • calendar.month_name – объект (массив), представляющий месяцы года в текущей локали с доступом по индексу, где 0 – пустая строка, 1 – январь, ..., 12 – декабрь.
  • calendar.month_abbr – объект (массив), представляющий сокращенные месяцы года в текущей локали с доступом по индексу, где 0 – пустая строка, 1 – январь, ..., 12 – декабрь.

Код Результат pythonCodes
# Импортируем модули.
import calendar, locale

# July и Jul.
print(calendar.month_name[7])
print(calendar.month_abbr[7])    

# Thursday и Thu.
print(calendar.day_name[3])    
print(calendar.day_abbr[3], end='\n\n')

# Установим руссую локализацию.
locale.setlocale(locale.LC_ALL, locale='ru_ru')

# Июль и июл.
print(calendar.month_name[7])
print(calendar.month_abbr[7])    

# четверг и Чт.
print(calendar.day_name[3])    
print(calendar.day_abbr[3]) 
July
Jul
Thursday
Thu

Июль
июл
четверг
Чт











 

Пример №13. Использование модуля calendar (часть 5).

Стоит добавить, что мы рассмотрели лишь основные встроенные инструменты для работы с датой и временем. В то же время большинство крупных библиотек и фрейворков предоставляют и свои инструменты, где-то более удобные и функциональные, а где-то и наоборот. В любом случае принцип работы везде похож, а выбор использования стандартных или предоставляемых дополнительно возможностей остается за программистом.

Краткие итоги параграфа

  • Основными инструментами для работы с датой и временем в Python являются модули стандартной библиотеки datetime, time и calendar. Все они используют в своей работе григорианский календарь и поддерживают стандарт UTC, по которому в мире регулируются часы и время.
  • Модуль datetime представляет собой инструмент, специализирующийся на обработке и форматировании даты и времени в привычном для человека виде. Тоже самое касается и модуля calendar, предназначенного для работы с календарями и связанными с ними функциями.
  • Поскольку стандартный модуль datetime не поддерживает автоматическое определение и конвертацию часовых поясов, для этих целей нужно использовать сторонние библиотеки такие, как pytz или dateutil.
  • Более старый модуль time предоставляет ряд возможностей для работы с системным временем и некоторые другие возможности, связанные с временем выполнения программ. При этом присутствуют возможности и для манипулирования обычными датой и временем. Но так как все они имеются в более специализированном модуле datetime, в современном коде чаще всего используется именно он.

Вопросы и задания для самоконтроля

1. Какие годы называются високосными? Как узнать, какой год является високосным, а какой нет? Показать решение.

Ответ. В григорианском календаре високосным называется год, который состоит из 366 дней. Високосные годы бывают каждые четыре года, исключая столетия, которые не делятся на 400 (например, 1600 и 2000 годы были високосными, а 1700, 1800 и 1900 годы високосными не были).

2. Перечислите основные модули стандартной библиотеки для работы с датой и временем. Показать решение.

Ответ. Основными инструментами для работы с датой и временем в Python являются модули стандартной библиотеки datetime, time и calendar. Все они используют в своей работе григорианский календарь и поддерживают стандарт UTC, по которому в мире регулируются часы и время.

3. Какой класс модуля datetime предназначен для работы с интервалами дат и времени? Показать решение.

Ответ. Для работы с интервалами дат и времени модуль datetime предоставляет класс timedelta, позволяющий выполнять над объектами дат и времени целый ряд математических операций: сложение, вычитание, умножение, деление и т.д.

4. Как можно получить количество секунд, прошедших с начала эпохи Unix? Показать решение.

Ответ. Для этого проще всего использовать метод time.time(), не забыв предварительно импортировать сам модуль time.

5. Как с помощью модуля calendar можно проверить, является ли год високосным? Показать решение.

Ответ. Для этого проще всего использовать метод calendar.isleap(year), не забыв предварительно импортировать сам модуль calendar.

6. Дополнительные упражнения и задачи по теме расположены в разделе «Дата и время» нашего сборника задач и упражнений.

Быстрый переход к другим страницам