4. Работа с датами и временем

4.1. Модуль datetime

Основной функционал для работы с датами и временем сосредоточен в модуле datetime в виде следующих классов:

  • date
  • time
  • datetime

4.1.1. Класс date

Для работы с датами воспользуемся классом date, который определен в модуле datetime. Для создания объекта date мы можем использовать конструктор date, который последовательно принимает три параметра: год, месяц и день:

date(year, month, day)

Например, создадим какую-либо дату:

import datetime

yesterday = datetime.date(2017,5, 2)
print(yesterday)      # 2017-05-02

Если необходимо получить текущую дату, то можно воспользоваться методом today():

from datetime import date

today = date.today()
print(today)      # 2017-05-03
print("{}.{}.{}".format(today.day, today.month, today.year))      # 2.5.2017

С помощью свойств day, month, year можно получить соответственно день, месяц и год.

4.1.2. Класс time

За работу с временем отвечает класс time. Используя его конструктор, можно создать объект времени:

time([hour] [, min] [, sec] [, microsec])

Конструктор последовательно принимает часы, минуты, секунды и микросекунды. Все параметры необязательные, и если мы какой-то параметр не передадим, то соответствующее значение будет инициализироваться нулем:

from datetime import time

current_time = time()
print(current_time)     # 00:00:00

current_time = time(16, 25)
print(current_time)     # 16:25:00

current_time = time(16, 25, 45)
print(current_time)     # 16:25:45

4.1.3. Класс datetime

Класс datetime из одноименного модуля объединяет возможности работы с датой и временем. Для создания объекта datetime можно использовать следующий конструктор:

datetime(year, month, day [, hour] [, min] [, sec] [, microsec])

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

from datetime import datetime

deadline = datetime(2017, 5, 10)
print(deadline)     # 2017-05-10 00:00:00

deadline = datetime(2017, 5, 10, 4, 30)
print(deadline)     # 2017-05-10 04:30:00

Для получения текущих даты и времени можно вызвать метод now():

from datetime import datetime

now = datetime.now()
print(now)     # 2017-05-03 11:18:56.239443

print("{}.{}.{}  {}:{}".format(now.day, now.month, now.year, now.hour, now.minute))  # 3.5.2017  11:21

print(now.date())
print(now.time())

С помощью свойств day, month, year, hour, minute, second можно получить отдельные значения даты и времени. А через методы date() и time() можно получить отдельно дату и время соответственно.

4.1.4. Преобразование из строки в дату

Из функциональности класса datetime следует отметить метод strptime(), который позволяет распарсить строку и преобразовать ее в дату. Этот метод принимает два параметра:

strptime(str, format)

Первый параметр str представляет строковое определение даты и времени, а второй параметр - формат, который определяет, как различные части даты и времени расположены в этой строке.

Для определения формата мы можем использовать следующие коды:

  • %d: день месяца в виде числа
  • %m: порядковый номер месяца
  • %y: год в виде 2-х чисел
  • %Y: год в виде 4-х чисел
  • %H: час в 24-х часовом формате
  • %M: минута
  • %S: секунда

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

from datetime import datetime
deadline = datetime.strptime("22/05/2017", "%d/%m/%Y")
print(deadline)     # 2017-05-22 00:00:00

deadline = datetime.strptime("22/05/2017 12:30", "%d/%m/%Y %H:%M")
print(deadline)     # 2017-05-22 12:30:00

deadline = datetime.strptime("05-22-2017 12:30", "%m-%d-%Y %H:%M")
print(deadline)     # 2017-05-22 12:30:00

4.2. Операции с датами

4.2.1. Форматирование даты и время

Для форматирования объектов date и time в обоих этих классах предусмотрен метод strftime(format). Этот метод принимает только один параметр, указывающий на формат, в который нужно преобразовать дату или время.

Для определения формата мы можем использовать один из следующих кодов форматирования:

  • %a: аббревиатура дня недели. Например, Wed - от слова Wednesday (по умолчанию используются английские наименования)
  • %A: день недели полностью, например, Wednesday
  • %b: аббревиатура названия месяца. Например, Oct (сокращение от October)
  • %B: название месяца полностью, например, October
  • %d: день месяца, дополненный нулем, например, 01
  • %m: номер месяца, дополненный нулем, например, 05
  • %y: год в виде 2-х чисел
  • %Y: год в виде 4-х чисел
  • %H: час в 24-х часовом формате, например, 13
  • %I: час в 12-ти часовом формате, например, 01
  • %M: минута
  • %S: секунда
  • %f: микросекунда
  • %p: указатель AM/PM
  • %c: дата и время, отформатированные под текущую локаль
  • %x: дата, отформатированная под текущую локаль
  • %X: время, форматированное под текущую локаль

Используем различные форматы:

from datetime import datetime
now = datetime.now()
print(now.strftime("%Y-%m-%d"))             # 2017-05-03
print(now.strftime("%d/%m/%Y"))             # 03/05/2017
print(now.strftime("%d/%m/%y"))             # 03/05/17
print(now.strftime("%d %B %Y (%A)"))        # 03 May 2017 (Wednesday)
print(now.strftime("%d/%m/%y %I:%M"))       # 03/05/17 01:36

При выводе названий месяцев и дней недели по умолчанию используются английские наименования. Если мы хотим использовать текущую локаль, но то мы можем ее предварительно установить с помощью модуля locale:

from datetime import datetime
import locale
locale.setlocale(locale.LC_ALL, "")

now = datetime.now()
print(now.strftime("%d %B %Y (%A)"))        # 03 Май 2017 (среда)

4.2.2. Сложение и вычитание даты и время

Нередко при работе с датами возникает необходимость добавить к какой-либо дате определенный промежуток времени или, наоборот, вычесть некоторый период. И специально для таких операций в модуле datetime определен класс timedelta. Фактически этот класс определяет некоторый период времени.

Для определения промежутка времени можно использовать конструктор timedelta:

timedelta([days] [, seconds] [, microseconds] [, milliseconds] [, minutes] [, hours] [, weeks])

В конструктор мы последовательно передаем дни, секунды, микросекунды, миллисекунды, минуты, часы и недели.

Определим несколько периодов:

from datetime import timedelta

three_hours = timedelta(hours=3)
print(three_hours)       # 3:00:00
three_hours_thirty_minutes = timedelta(hours=3, minutes=30)  # 3:30:00

two_days = timedelta(2)  # 2 days, 0:00:00

two_days_three_hours_thirty_minutes = timedelta(days=2, hours=3, minutes=30)  # 2 days, 3:30:00

Используя timedelta, мы можем складывать или вычитать даты. Например, получим дату, которая будет через два дня:

from datetime import timedelta, datetime

now = datetime.now()
print(now)                      # 2017-05-03 17:46:44.558754
two_days = timedelta(2)
in_two_days = now + two_days
print(in_two_days)              # 2017-05-05 17:46:44.558754

Или узнаем, сколько было времени 10 часов 15 минут назад, то есть фактически нам надо вычесть из текущего времени 10 часов и 15 минут:

from datetime import timedelta, datetime

now = datetime.now()
till_ten_hours_fifteen_minutes = now - timedelta(hours=10, minutes=15)
print(till_ten_hours_fifteen_minutes)

4.2.3. Свойства timedelta

Класс timedelta имеет несколько свойств, с помощью которых мы можем получить временной промежуток:

  • days: возвращает количество дней
  • seconds: возвращает количество секунд
  • microseconds: возвращает количество микросекунд

Кроме того, метод total_seconds() возвращает общее количество секунд, куда входят и дни, и собственно секунды, и микросекунды.

Например, узнаем какой временной период между двумя датами:

from datetime import timedelta, datetime

now = datetime.now()
twenty_two_may = datetime(2017, 5, 22)
period = twenty_two_may - now
print("{} дней  {} секунд   {} микросекунд".format(period.days, period.seconds, period.microseconds))
# 18 дней  17537 секунд   72765 микросекунд

print("Всего: {} секунд".format(period.total_seconds()))
# Всего: 1572737.072765 секунд

4.2.4. Сравнение дат

Также как и строки числа и даты можно сравнивать с помощью стандартных операторов сравнения:

from datetime import datetime

now = datetime.now()
deadline = datetime(2017, 5, 22)
if now > deadline:
    print("Срок сдачи проекта прошел")
elif now.day == deadline.day and now.month == deadline.month and now.year == deadline.year:
    print("Срок сдачи проекта сегодня")
else:
    period = deadline - now
    print("Осталось {} дней".format(period.days))

4.2.5. Упражнения

  1. Используя примеры программ: напишите программу, которая вычисляет сколько месяцев назад вы пошли в школу.
  2. Используя примеры программ: напишите программу, которая вычисляет сколько дней вам осталось до окончания школы.