Все курсы > Программирование на Питоне > Занятие 5
Говоря про временные ряды, мы уже начали анализировать данные, в которых присутствует дата и время (в частности, в библиотеке Pandas). Сегодня мы сделаем шаг назад и посмотрим в целом как работать с датой и временем в Питоне.

Модуль datetime
В базовом функционале Питона нет отдельного типа данных, отвечающего за дату и время. Необходимо импортировать модуль, который называется datetime.
Первая особенность, про которую стоит сказать, datetime — это не только название модуля, но и название одного из классов внутри этого модуля. Помимо класса datetime, нас будет интересовать ещё один класс — timedelta.

Перейдем к практике.
Откроем ноутбук к этому занятию⧉
Импорт модуля и класса datetime
Самый простой способ — импортировать весь модуль datetime.
1 2 |
# импортируем весь модуль import datetime |
Далее предположим, что мы хотим воспользоваться функцией now(), которая находится внутри класса datetime. Функция now() выводит текущие дату и время.
1 2 |
# чтобы получить доступ к функции now(), сначала обратимся к модулю, потом к классу print(datetime.datetime.now()) |
1 |
2021-11-18 09:33:28.140594 |
Как вы видите, это не очень удобно. Можно импортировать только класс datetime и обращаться непосредственно к нему.
1 2 |
from datetime import datetime print(datetime.now()) |
1 |
2021-11-18 09:33:30.586757 |
Объект datetime и функция now()
Теперь поговорим подробнее про то, что выводит функция now().
1 2 3 |
# поместим созданный с помощью функции now() объект datetime в переменную cur_dt cur_dt = datetime.now() print(cur_dt) |
1 |
2021-11-18 09:33:32.412999 |
На выходе мы получаем текущие дату и время по UTC⧉, потому что серверы Google Colab настроены именно на это время (московское время, например, отличается на +3 часа). Сам вывод состоит из следующих компонентов.

Мы можем обратиться к каждому из этих компонентов по отдельности.
1 2 |
# с помощью соответствующих атрибутов выведем каждый из компонентов объекта print(cur_dt.year, cur_dt.month, cur_dt.day, cur_dt.hour, cur_dt.minute, cur_dt.second, cur_dt.microsecond) |
1 |
2021 11 18 9 33 32 412999 |
Мы также можем посмотреть на день недели, причем в двух форматах. Метод .weekday() считает, что неделя начинается с нуля, метод .isoweekday(), что с единицы.

Так как 18 ноября 2021 года — это четверг, то применив эти методы, мы должны получить цифры три и четыре соответственно.
1 |
print(cur_dt.weekday(), cur_dt.isoweekday()) |
1 |
3 4 |
Разумеется, когда вы будете самостоятельно исполнять код в ноутбуке, будут выведены текущие дата и время сервера Google.
Объект datetime, полученный из функции now(), не содержит данных о часовом поясе.
1 2 |
# посмотрим на часовой пояс с помощью атрибута tzinfo print(cur_dt.tzinfo) |
1 |
None |
Для того чтобы добавить такую информацию и вывести, например, другой часовой пояс, нам нужно воспользоваться модулем pytz.
1 2 3 4 5 |
import pytz # выведем текущее время в Москве dt_moscow = datetime.now(pytz.timezone('Europe/Moscow')) print(dt_moscow) |
1 |
2021-11-18 12:33:33.682674+03:00 |
Посмотрим, не появился ли часовой пояс.
1 |
print(dt_moscow.tzinfo) |
1 |
Europe/Moscow |
Timestamp
До сих пор мы работали с привычным для нас делением на годы, месяцы, дни, часы, минуты и секунды. При этом компьютеры используют так называемое время Unix, которое отсчитывается в секундах c первого января 1970 года. Для отображения даты и времени в таком формате в Питоне есть объект timestamp (по-английски — «временная отметка»).
1 2 |
# получим timestamp текущего времени с помощью метода .timestamp() timestamp = datetime.now().timestamp() |
Посмотрим, сколько секунд и микросекунд прошло с 01.01.1970 и до момента исполнения кода.
1 |
print(timestamp) |
1 |
1637233979.128056 |
Не составляет труда вернуть timestamp обратно в привычный формат.
1 2 |
# для этого воспользуемся методом .fromtimestamp() print(datetime.fromtimestamp(timestamp)) |
1 |
2021-11-18 11:12:59.128056 |
Создание объекта datetime вручную
Дату и время не обязательно получать из функции now(). Мы вполне можем передать объекту datetime наши собственные параметры, например, день рождения Питона.
1 2 3 |
# передадим объекту datetime 20 февраля 1991 года hb = datetime(1991, 2, 20) print(hb) |
1 |
1991-02-20 00:00:00 |
Обратите внимание, мы ввели только год, месяц и день. Это обязательные параметры. Остальные параметры можно не вводить, в этом случае они заполнятся нулями.
Из этого объекта мы также можем извлечь компоненты (год, месяц, число и т.д.) и создать timestamp.
1 2 |
# извлечем год с помощью атрибута year print(hb.year) |
1 |
1991 |
1 2 |
# и создадим timestamp print(datetime.timestamp(hb)) |
1 |
667008000.0 |
Преобразование строки в datetime и наоборот
Строка в datetime через .strptime()
Если дата содержится в строковом формате, Питон не сможет извлечь из нее компоненты. Предварительно строку нужно преобразовать. Для этого есть метод .strptime().
1 2 3 |
# дана строка с датой 2 декабря 2007 года и временем 12 часов 30 минут и 45 секунд str_to_dt = '2007-12-02 12:30:45' type(str_dt) |
1 |
str |
Преобразуем эту строку в объект datetime с помощью метода .strptime().
1 2 3 4 |
res_dt = datetime.strptime(str_to_dt, '%Y-%m-%d %H:%M:%S') print(res_dt) print(type(res_dt)) |
1 2 |
2007-12-02 12:30:45 <class 'datetime.datetime'> |
Как вы видите, сначала мы передаём этому методу саму строку, а затем тот формат, в котором содержится дата и время (иначе Питон не поймет, к чему относится конкретное число).
Давайте расшифруем каждое из обозначений:
- %Y — год в формате ГГГГ, например: 1995, 2003 и т.д.
- %m — месяц в виде числа с нулями, например, январь — 01, февраль — 02 и т.д.
- %d — день месяца в виде числа с нулями, например: 01, 02, …, 31
- %H — час в 24-часовом формате в виде числа с нулями, например: 00, 01, …, 23
- %M — минуты в виде числа с нулями, например: 00, 01, …, 59
- %S — секунды в виде числа с нулями, например: 00, 01, …, 59
Дефисы, пробелы, двоеточия или, например, запятые — тоже элементы формата и их тоже нужно указывать.
Datetime в строку через .strftime()
Обратное преобразование также возможно. Это может быть полезно, если мы захотим вывести дату и время в строго определенном формате.
1 2 3 |
# вначале создадим объект datetime и передадим ему 19 ноября 2002 года dt_to_str = datetime(2002, 11, 19) type(dt_to_str) |
1 2 3 4 5 |
# преобразуем объект в строку в формате "день недели, месяц число, год" res_str = datetime.strftime(dt_to_str, '%A, %B %d, %Y') print(res_str) print(type(res_str)) |
1 2 |
Tuesday, November 19, 2002 <class 'str'> |
Метод .strftime() можно применять непосредственно к объекту datetime.
1 |
dt_to_str.strftime('%A, %B %d, %Y') |
1 |
'Tuesday, November 19, 2002' |
Расшифруем обозначения:
- %A — полное название дня недели, например: Sunday, Monday, …
- %B — полное название месяца, например: January, February
- %d — день месяца в виде числа с нулями, например: 01, 02, …, 31
- %Y — год в формате ГГГГ, например: 1999, 2003 и т.д.
Более подробный перечень обозначений можно найти в ноутбуке к занятию⧉.
Сравнение и арифметика дат
Сравнение дат
Даты можно сравнивать между собой. Для этого используются стандартные операторы сравнения >, <, >=, <=, ==, !=.
Обратите внимание, что большей считается более поздняя дата.
Сравним две даты публикации работ Эйнштейна.
1 2 |
date1 = datetime(1905, 6, 30) # "К электродинамике движущихся тел" date2 = datetime(1916, 5, 11) # Общая теория относительности |
Вторая дата должна быть «больше», потому что она более поздняя.
1 |
date1 < date2 |
1 |
True |
Обратное будет признано ложным.
1 |
date1 > date2 |
1 |
False |
Календарный и алфавитный порядок дат
Интересно, что если даты записаны в виде строки в формате ГГГГ.ММ.ДД, то в Питоне мы можем их сравнивать, как если бы мы сравнивали объекты datetime. Другими словами, календарный и алфавитный порядок дат совпадают. Приведем пример.
1 2 |
# вначале запишем даты в виде строки и сравним их '2007-12-02' > '2002-11-19' |
1 |
True |
1 2 |
# теперь в виде объекта datetime datetime(2007, 12, 2) > datetime(2002, 11, 19) |
1 |
True |
Промежуток времени и класс timedelta
Если из большей даты вычесть меньшую, то мы получим временной промежуток между датами.
1 2 |
diff = date2 - date1 print(diff) |
1 |
3968 days, 0:00:00 |
При этом результат будет храниться в специальном объекте timedelta.
1 |
type(diff) |
1 |
datetime.timedelta |
Атрибут days позволяет посмотреть только дни.
1 |
print(diff.days) |
1 |
3968 |
Объект timedelta также можно создать вручную.
1 2 3 4 5 |
# для этого вначале импортируем соответствующий класс from datetime import timedelta # а затем создадим объект timedelta продолжительностью 1 день timedelta(days = 1) |
1 |
datetime.timedelta(days=1) |
Арифметика дат
Объединив объекты datetime и timedelta, мы можем «путешествовать во времени».
1 2 3 |
# допустим сейчас 1 января 2070 года future = datetime(2070, 1, 1) future |
1 |
datetime.datetime(2070, 1, 1, 0, 0) |
И мы хотим отправиться в 1 января 1900 года, т.е. на 170 лет назад.
1 2 3 4 5 6 7 8 |
# сначала просто умножим 365 дней на 170 time_travel = timedelta(days = 365) * 170 # а потом переместимся из будущего в прошлое past = future - time_travel # к сожалению, мы немного "не долетим", потому что не учли високосные годы, в которых 366 дней past |
1 |
datetime.datetime(1900, 2, 12, 0, 0) |
Давайте посмотрим, сколько дней мы преодолели.
1 |
365 * 170 |
1 |
62050 |
Предлагаю узнать, сколько дней нам на самом деле нужно было пролететь. Мы уже умеем это делать, находя разницу между двумя объектами datetime.
1 |
datetime(2070, 1, 1) - datetime(1900, 1, 1) |
1 |
datetime.timedelta(days=62092) |
Теперь снова совершим путешествие во времени, но на этот раз укажем правильное количество дней.
1 2 3 4 |
time_travel = timedelta(days = 62092) past = future - time_travel past |
1 |
datetime.datetime(1900, 1, 1, 0, 0) |
Объект timedelta можно также прибавлять к объекту datetime. Например, нам может быть нужно создать перечень дат, пусть это будут новогодние празники в 2021 году. Для этого удобно использовать цикл while.
1 2 3 4 5 6 7 8 9 10 11 |
cur_date = datetime(2021, 1, 1) # эту дату мы будем выводить end_date = datetime(2021, 1, 10) # это граница (условие в цикле while) # пока верно условие while cur_date <= end_date: # выведем cur_date в формате "месяц число, год" print(cur_date.strftime('%b %d, %Y')) # прибавим к выводимой дате один день cur_date += timedelta(days = 1) |
1 2 3 4 5 6 7 8 9 10 |
Jan 01, 2021 Jan 02, 2021 Jan 03, 2021 Jan 04, 2021 Jan 05, 2021 Jan 06, 2021 Jan 07, 2021 Jan 08, 2021 Jan 09, 2021 Jan 10, 2021 |
Дата и обработка ошибок
Конструкция try / except и оператор pass
Прежде чем мы перейдем к практическому примеру с обработкой дат, давайте познакомимся с одной полезной конструкцией. Часто мы не уверены, что наш код отработает без ошибок. Например, в данных может содержаться неточность, о которой мы ничего не знаем. При этом нам не хотелось бы, чтобы исполнение кода остановилось.
Для этого в Питоне есть конструкция try/except.

Приведем пример.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# пусть дан список чисел в строковом формате, и мы хотим посчитать их сумму # предположим, буква "а" попала в список случайно numbers = ['5', '10', 'a', '15', '10'] # объявим переменную суммы total = 0 # пройдемся по числам for number in numbers: # попробуем прибавить число к переменной total try: total += int(number) # если же этого сделать не удастся except: # перейдем к следующему числу pass # выведем сумму total |
1 |
40 |
Если бы такой конструкции не было, при попытке прибавить букву «а» алгоритм вывел бы ошибку.
Оператор pass просто говорит алгоритму продолжить работу. Вместо него можно вывести предупреждение.
1 2 3 4 5 6 7 8 9 |
total = 0 for number in numbers: try: total += int(number) except: print(f'Элемент \'{number}\' обработать не удалось') total |
1 2 |
Элемент 'a' обработать не удалось 40 |
Примечание. Обратите внимание на запись \'{number}\'. Обратная косая черта необходима, чтобы Питон воспринимал кавычки как часть строки.
Обработка нескольких форматов дат
Теперь давайте посмотрим, как эта конструкция работает с датами. Вначале скачаем и подгрузим в Google Colab данные среднемесячной температуры в Нью-Йорке в 2002 году (в градусах Фаренгейта).
На данном этапе вы уже должны быть экспертами по работе с внешними данными.
1 2 3 4 |
# посмотрим на данные import pandas as pd temp = pd.read_csv('temperature.csv') temp |

Предположим, что мы хотим вручную преобразовать каждую дату из строки в объект datetime. Теперь допустим, что проанализировав данные, мы выявили три шаблона: ГГГГ.ММ.ДД, ГГГГ.ММ.Д и ГГГГ.ММ. Напишем код, который в цикле for преобразует эти даты в объект datetime. Дополнительно наш код должен посчитать количество не обработанных записей.
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 |
# создадим список с известными нам шаблонами formats = ['%Y-%m-%d', '%Y-%m-%-d', '%Y-%m'] # создадим счетчик для записей, которые не обработались counter = 0 # пройдемся в цикле по столбцу Date for d in temp.Date: # затем пройдемся по известным нам форматам for format in formats: # попробуем, применив каждый из форматов, # преобразовать строку с датой в объект datetime try: print(datetime.strptime(d, format)) counter += 1 # если что-то пошло не так except: # перейдем к следующему формату (второй цикл for) или записи (первый цикл for) pass # посмотрим, сколько записей не обработалось print('Не обработалось записей:', len(temp) - counter) |
1 2 3 4 5 6 7 8 9 10 11 12 |
2002-01-01 00:00:00 2002-02-01 00:00:00 2002-03-01 00:00:00 2002-04-01 00:00:00 2002-05-01 00:00:00 2002-06-01 00:00:00 2002-07-01 00:00:00 2002-08-01 00:00:00 2002-09-01 00:00:00 2002-10-01 00:00:00 2002-12-01 00:00:00 Не обработалось записей: 1 |
Как мы видим, один формат мы все же упустили (данные за ноябрь в формате ММ.ГГГГ), и Питон не смог обработать эту запись.
Эту же работу мы можем поручить библиотеке Pandas через функцию read_csv() и параметр parse_dates (мы уже делали так, изучая временные ряды).
1 2 |
temp_parsed = pd.read_csv('temperature.csv', index_col = 'Date', parse_dates = True) temp_parsed |

В данном случае нам удалось обработать все записи, включая данные за ноябрь.
1 2 |
# индекс превратился в объект datetime type(temp_parsed.index) |
1 |
pandas.core.indexes.datetimes.DatetimeIndex |
Иногда, как мы видим, решение «из коробки» (то есть уже готовое решение) более эффективно, чем написанный самостоятельно код.
Подведем итог
Сегодня мы посмотрели на возможности Питона по работе с датой и временем. В частности, узнали про классы datetime и timedelta модуля datetime и научились работать с объектами этих классов:
- Мы рассмотрели структуру объекта datetime
- Узнали про функцию now()
- Научились извлекать timestamp и вручную создавать объект datetime
- Посмотрели, как преобразовывать строку в объект datetime и наоборот
- Изучили возможности сравнения дат, вычисления промежутка между датами и выполнили несложную арифметику дат с помощью объекта timedelta
- Наконец, мы познакомились с конструкцией try/except и оператором pass и применили их к обработке различных форматов дат
Вопросы для закрепления
С какими классами модуля datetime мы познакомились на этом занятии?
Посмотреть правильный ответ
Ответ: классом datetime и классом timedelta
Чему соответствует формат ‘%c’?
Посмотреть правильный ответ
Ответ: формат ‘%c’ выводит полную дату и время, например: Sun Nov 21 10:38:12 2021
Как еще в библиотеке Pandas мы можем превратить столбец в индекс и затем преобразовать в объект datetime? Подсказка: обратитесь к лекции по временным рядам.
Посмотреть правильный ответ
Ответ: мы можем последовательно применить .set_index() и pd.to_datetime()
В ноутбуке к лекции приведены дополнительные упражнения⧉.
На следующем занятии мы поговорим про функции в Питоне.