Автоматизация с Python

Работа с датами в Python

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

Вы боретесь при работе с объектами DateTime? Ну, я должен признать, что я часто борюсь. Мне всегда нужно много искать, чтобы найти подходящие методы для моего варианта использования. Тогда я решил написать эту статью, как документацию для моих дорогих читателей и себя.

Фон

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

Имя файла обычно представляет собой комбинацию имени отчета, даты или периода отчета и расширения файла — например, периодический отчет с именем «Отчет о потреблении электроэнергии 2022_Q4_WW43.xlsx» и ежедневный отчет с именем "Отчет о заявке на инструменты 20221021.csv". Чтобы получить правильные файлы, нам нужно будет рассчитать дату или период в имени файла на основе времени работы инструмента автоматизации отчетов.

При этом данная статья будет структурирована следующим образом:

  1. Анализ и форматирование DateTime (strptime vs strftime)
  2. Извлечение информации о годе / месяце / дне
  3. Рассчитать мировую неделю по дате
  4. Рассчитать день недели по дате
  5. Преобразовать объект DateTime в период
  6. Вычислить временной интервал данных

Давайте начнем!

Разбор DateTime означает, что мы преобразуем строковый объект, содержащий дату, в объект DateTime. Например, когда мы получаем дату из отчета "Tools Requisition Report 20221021.csv" с помощью регулярного выражения или любого другого метода, дата "20221021" будет строковой переменной.

После того, как мы проанализируем его, он станет объектом DateTime и будет записан в формате ISO (ГГГГ-ММ-ДД), 2022–10–21. Затем мы можем отформатировать его в определенном формате, например, 21 октября 2022 года. Обратите внимание, что объект DateTime станет строковым объектом после того, как мы его отформатировали.

Сбивает с толку? Не волнуйся!

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

1. Разбор и форматирование DateTime

Разбор даты и времени

В библиотеке DateTime есть два метода для анализа даты:

  • datetime.fromisoformat()
  • datetime.strptime()

Давайте посмотрим, в чем разница между ними!

import datetime as dt
my_date1 = "2022-07-01"
print(my_date1)
print(type(my_date1))
my_date2 = "01-07-2022"
print(my_date2)
print(type(my_date2))
my_date3 = "01July2022"
print(my_date3)
print(type(my_date3))

Итак, я создал 3 разные даты в качестве переменных, на данный момент это строковые объекты. Давайте теперь разберем их в объект DateTime.

my_date1a = dt.datetime.fromisoformat(my_date1)
print(type(my_date1a))
my_date3a = dt.datetime.fromisoformat(my_date3)
print(type(my_date3a))

Для первого метода, datetime.fromisoformat(), как и для имени метода, он может анализировать только дату в формате ISO, ГГГГ-ММ-ДД, как в переменной с именем my_date1. Следовательно, когда мы пытаемся использовать этот метод для других форматов DateTime, как в my_date3, он возвращает Ошибку значения. Переменная my_date1a — это объект DateTime, который мы получаем, анализируя переменную my_date1.

Ниже приведен пример разбора даты методом datetime.strptime(). Для этого метода мы должны указать код формата на основе формата даты для анализа даты. Вы можете прочитать больше о коде формата в разделе Поведение strftime() и strptime().

# my_date2 = "01-07-2022"
my_date2a = dt.datetime.strptime(my_date2, "%d-%m-%Y")
print(type(my_date2a))
print(my_date2a)
# Output:
# <class 'datetime.datetime'>
# 2022-07-03 00:00:00

Давайте посмотрим на другой пример с другим форматом даты.

# my_date3 = "01July2022"
my_date3a = dt.datetime.strptime(my_date3, "%d%B%Y")
print(type(my_date3a))
print(my_date3a)
# Output:
# <class 'datetime.datetime'> 
# 2022-07-01 00:00:00

Анализ даты с помощью метода strptime() заключается в замене дня, месяца и года соответствующими кодами формата. Как показано в приведенном выше примере, %d — день, %m — цифра месяца, %B — полное название месяца и %Y — год с веком.

Что ж, пока это может показаться очень сложным, если вы новичок в этом, но я уверяю вас, что у вас все получится, как только вы ознакомитесь с кодом формата. Помните, вы всегда можете обратиться к strftime() и strptime() Behavior. 😉

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

После того, как мы разберем строковый объект в объект DateTime, он будет показан в формате ISO. Если вы хотите, чтобы это было в других формах, мы должны использовать метод datetime.strftime() для форматирования даты.

# my_date3a: 2022-07-01 00:00:00
my_format_date = dt.datetime.strftime(my_date3a, "%B %d, %Y")
print(my_format_date)
# Output:
# July 01, 2022

Обратите внимание, что после того, как мы отформатируем дату, она станет строкой.

После того, как мы разобрали строку в объект DateTime, мы можем получить из нее информацию.

2. Извлечение информации о годе/месяце/дне

Примечание. В приведенном ниже примере используется переменная из примера в первом разделе.

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

  • datetime_object.year
  • datetime_object.month
  • datetime_object.day
# my_date3a: 2022-07-01 00:00:00
# Get Year Info
my_date3a.year
# Output: 
# 2022
# Get Month Info
my_date3a.month
# Output: 
# 7
# Get Day Info
my_date3a.day
# Output: 
# 1

Простой не так ли? 😄

Однако мы не можем извлечь указанную выше информацию из отформатированной даты.

# my_format_date = "July 01, 2022"
my_format_date.month

Он вернет ошибку атрибута. Это связано с тем, что когда мы отформатировали дату в других форматах, она снова станет строковым объектом. Мы можем вернуть атрибуты DateTime только из объекта DateTime.

print(type(my_date3a))
print(type(my_format_date))
Output:
<class 'datetime.datetime'> 
<class 'str'>

Имейте в виду, что результат strftime() — это строковый объект, а результат strptime() — объект DateTime.

3. Рассчитать мировую неделю по дате

Примечание. В этом разделе для примера мы будем использовать новые переменные.

Сначала я создаю два новых строковых объекта с разными датами, а затем анализирую их в объекты DateTime.

import datetime as dt
my_date_str_1 = "2022-07-01"
my_date_1 = dt.datetime.strptime(my_date_str_1, "%Y-%m-%d")
print(my_date_1)
my_date_str_2 = "2022-07-03"
my_date_2 = dt.datetime.strptime(my_date_str_2, "%Y-%m-%d")
print(my_date_2)
# Output:
# 2022-07-01 00:00:00 
# 2022-07-03 00:00:00

Мы будем использовать метод isocalendar() для получения информации о мировой неделе из объекта DateTime. Это связано с тем, что объект DateTime не имеет атрибута мировой недели.

print(my_date_1.isocalendar())
print(my_date_2.isocalendar())
# Output:
# datetime.IsoCalendarDate(year=2022, week=26, weekday=5) 
# datetime.IsoCalendarDate(year=2022, week=26, weekday=7)

Метод isocalendar() вернет кортеж, содержащий год ISO, номер недели и день недели. День недели будет возвращен в виде числа. Мы можем вернуть значение с соответствующим индексом.

print("Date 1: 2022-07-01")
print("Year:", my_date_1.isocalendar()[0])
print("World Week Number: ", my_date_1.isocalendar()[1])
print("Weekday: ", my_date_1.isocalendar()[2])
print("Date 2: 2022-07-03")
print("Year:", my_date_2.isocalendar()[0])
print("World Week Number: ", my_date_2.isocalendar()[1])
print("Weekday: ", my_date_2.isocalendar()[2])
# Output:
# Date 1: 2022-07-01 
# Year: 2022 
# World Week Number:  26 
# Weekday:  5 
# Date 2: 2022-07-03 
# Year: 2022 
# World Week Number:  26 
# Weekday:  7

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

4. Рассчитать день недели по дате

Примечание. В приведенном ниже примере используется переменная из примера в разделе 3.

Существует несколько способов вернуть информацию о дне недели из даты. Один из способов — через isocalendar(), как показано в предыдущем разделе. Другой метод использует метод weekday(), показанный ниже.

print("Date 1: 2022-07-01")
print("Weekday: ", my_date_1.weekday())
print("Date 2: 2022-07-03")
print("Weekday: ", my_date_2.weekday())
# Output:
# Date 1: 2022-07-01 
# Weekday:  4 
# Date 2: 2022-07-03 
# Weekday:  6

Что ж, 2022–07–01 — пятница. Метод isocalendar() не соответствует правилу индекса Python. Таким образом, оба метода isocalendar() и weekday() начинают отсчет в понедельник, но isocalendar() использует индекс, начинающийся с 1, а weekday() — это функция Python, которая начинается с 0. Два упомянутых метода возвращают день недели в виде чисел. Есть еще один способ сделать это, угадаете🤔?

Это метод strftime().

Мы можем получить название дня недели, отформатировав дату соответствующим кодом формата.

date_weekday_1 = dt.datetime.strftime(my_date_1, "%a")
print(date_weekday_1)
date_weekday_2 = dt.datetime.strftime(my_date_2, "%a")
print(date_weekday_2)
# Output:
# Fri 
# Sun

Мы можем вернуть сокращенное название дня недели, отформатировав его, используя код формата «%a», как показано в примере выше, или вернуть полное название дня недели, используя код формата «%A», как показано в примере ниже.

date_weekday_1 = dt.datetime.strftime(my_date_1, "%A")
print(date_weekday_1)
date_weekday_2 = dt.datetime.strftime(my_date_2, "%A")
print(date_weekday_2)
# Output:
# Friday 
# Sunday

Мы также можем вернуть день недели в виде числа.

date_weekday_1 = dt.datetime.strftime(my_date_1, "%w")
print(date_weekday_1)
date_weekday_2 = dt.datetime.strftime(my_date_2, "%w")
print(date_weekday_2)
# Output:
# 5 
# 0

Забавный факт, когда вы используете метод strftime(), отсчет начинается с воскресенья, а индекс начинается с 0, как показано в документации.

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

5. Преобразование объекта DateTime в период

Примечание. В этом разделе для примера мы будем использовать новые переменные.

Мы уже рассмотрели методы и атрибуты для возврата года, месяца, дня, номера мировой недели и дня недели. Если вы все еще помните пример названия отчета, который я привел в начале этой статьи, "Отчет о потреблении электроэнергии за 2022_Q4_WW43.xlsx", мы еще не получили еще одну часть информации, а именно квартал.

Чтобы получить квартал из даты, мы должны использовать библиотеку pandas вместе с библиотекой DateTime.

import pandas as pd
import datetime as dt
# pandas.Timestamp.to_period
date_1 = '2022-10-21'
timestamp_1 = pd.Timestamp(date_1)

Сначала мы создаем дату как строковый объект, а затем конвертируем ее в метку времени. После этого мы можем преобразовать метку времени в период.

year_period = timestamp_1.to_period(freq='Y')
month_period = timestamp_1.to_period(freq='M')
week_period = timestamp_1.to_period(freq='W')
quarter_period = timestamp_1.to_period(freq='Q')
print("Year: ", year_period)
print("Month: ", month_period)
print("Week: ", week_period)
print("Quarter: ", quarter_period)
# Output:
# Year:  2022 
# Month:  2022-10 
# Week:  2022-10-17/2022-10-23 
# Quarter:  2022Q4

Это довольно просто, верно?

Согласно официальной документации pandas, для метода pandas.Timestamp.to_period() существует всего 4 типа вывода. В предыдущих разделах мы получаем год, месяц и неделю отдельно. Затем этот метод вместо этого возвращает конкретный период даты. Например, 2022Q4 относится к 4-му кварталу 2022 года.

Требуется еще один шаг, чтобы получить только «Q4» вместо «2022Q4». Переменная quarter_period теперь является объектом периода. Итак, нам нужно преобразовать его в строковый объект, а затем вернуть последние две строки, чтобы получить «Q4».

print(str(quarter_period))[-2:]

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

# Output:
# Q4

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

6. Рассчитать интервал DataTime

Примечание. В этом разделе для примера мы будем использовать новые переменные.

Существует два типа расчета интервала DateTime:

  1. Вычислить интервал между двумя датами
  2. Добавить/минус временной интервал к дате

Давайте посмотрим их один за другим!

Перед этим давайте создадим несколько дат для примера.

import datetime as dt
my_date1 = dt.datetime.fromisoformat("2022-07-01")
my_date2 = dt.datetime.fromisoformat("2022-07-05")

Вычислить интервал между двумя датами

Вычислить интервал между двумя датами очень просто. Нам просто нужен минус одна дата от другой.

print(my_date2 - my_date1)
# Output:
# datetime.timedelta(days=4)

На выходе будет timedelta, которая относится к разнице между двумя объектами DateTime.

Добавить/минус временной интервал к дате

Другой пример — добавить или вычесть временной интервал к дате.

from datetime import timedelta
print(my_date2 - timedelta(days=10))
print(my_date2 + timedelta(days=10))
print(my_date2 - timedelta(seconds=10))
print(my_date2 + timedelta(seconds=10))
# Output:
# 2022-06-25 00:00:00 
# 2022-07-15 00:00:00
# 2022-07-04 23:59:50 
# 2022-07-05 00:00:10

Для этой операции мы будем использовать класс timedelta из библиотеки DateTime. Этот класс позволяет нам добавлять/отнимать дни, секунды или микросекунды к/от даты.

Заключение

В заключение были показаны методы преобразования строкового объекта в объект DateTime и форматирования объекта DateTime в определенный формат. Затем обсуждаются способы получения года, месяца, дня, мировой недели, а также дня недели из даты.

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

Наконец, объясняются два типа расчета интервала DateTime, который вычисляет интервал между двумя датами и добавляет/отнимает временной интервал к дате.

С помощью всех методов и примеров, которые я показал, можете ли вы воссоздать приведенные ниже имена файлов с сегодняшней датой (26.10.2022)? 😎 Напишите свой ответ в комментарии!

  • "Отчет о потреблении электроэнергии за 2022_Q4_WW43.xlsx"
  • "Отчет о заявке на инструменты 20221021.csv"

Ответ внизу статьи. Попробуйте сами, прежде чем проверять ответ! 😉

Надеюсь, вам понравится читать эту статью, и я надеюсь, что она поможет вам лучше понять, как работать с объектом DateTime в Python. Спасибо! 😊

Оставайся на связи

Подпишитесь на Ютуб

Примечание

В статье Советы по автоматизации отчетов с помощью Python я объяснил некоторые советы по автоматизации отчетов. Проверьте это!

Рекомендации

  1. Документация Python по модулю DateTime
  2. Документация pandas.Timestamp.to_period
  3. Поведение strftime() и strptime()

Спасибо и поздравляю с тем, что дочитали до конца 😊!

Отвечать:

Надеюсь, вы поняли правильно! 😊