DevGang
Авторизоваться

Путешествие во времени стало проще: Полное руководство по Python Datetime

Вероятно, все, что вам когда-либо понадобится для Python Datetime

Работа с данными, содержащими дату и время, может быть легко утомительной, особенно если вы не совсем знакомы с тонкостями манипулирования датой и временем. Многие термины, такие как DatetimeIndex, Timestamp, Timedelta, Timezone и Offset, могут сбивать с толку даже аналитиков среднего уровня. Это руководство поможет вам освоить манипулирование датой и временем и получить ценную информацию из ваших данных. Давайте начнем!

Модуль datetime в стандартной библиотеке Python предоставляет классы, которые могут работать с датами, временем и временными интервалами¹. Этот модуль особенно важен при анализе данных, поскольку даты и время часто являются ключевыми компонентами данных, и точное управление ими необходимо для таких проектов, как анализ временных рядов и финансовое моделирование. С помощью даты и времени аналитики могут лучше понять временные тенденции и закономерности в данных, что может привести к более точным выводам и прогнозам на основе набора данных. 6 классов в модуле datetime включают date, time, datetime, timedelta, tzinfo и timezone.

Осведомленные и наивные объекты datetime

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

from datetime import datetime
import pytz

tz = pytz.timezone('Asia/Singapore')
dt = datetime(2023, 5, 4, 10, 30, 0, tzinfo=tz)

Это создает осведомленный объект datetime, представляющий 4 мая 2023 года в 10:30 по сингапурскому времени. Аргумент tzinfo указывает часовой пояс для объекта datetime. Распечатав dt, мы получим следующую информацию: datetime.datetime(2023, 5, 4, 10, 30, tzinfo=<DstTzInfo ‘Asia/Singapore’ LMT+6:55:00 STD>).

С другой стороны, наивный объект datetime не содержит информации о часовом поясе. Он представляет дату и время, но неясно, к какому часовому поясу относятся эти дата и время¹.

from datetime import datetime

dt = datetime(2023, 5, 4, 10, 30, 0)

Вызов атрибута dt.tzinfo и dt.utcoffset дает None.

Стоит отметить, что осведомленные объекты datetime всегда находятся во внутреннем времени UTC, и они настраиваются на указанный часовой пояс при отображении или использовании в вычислениях. Это означает, что вы можете напрямую сравнивать объекты datetime из разных часовых поясов, поскольку оба они внутренне представлены во времени UTC. Чаще всего лучше использовать объекты с поддержкой datetime везде, где это возможно, особенно в приложениях, которые имеют дело с данными из различных часовых поясов.

Всемирное координированное время (UTC), Time, Timezone и Offset

UTC, или универсальное скоординированное время, является основным стандартом времени, используемым во всем мире для регулирования часов и времени. До 1972 года оно было известно как среднее время по Гринвичу (GMT)². UTC — это стандарт времени, признанный и согласованный во всем мире, что делает его незаменимым для международной связи, навигации и научных исследований. Стоит отметить, что переход на летнее время не влияет на UTC, что делает его стабильной точкой отсчета для действий, связанных со временем. Вместо этого он основан на атомных часах и настраивается по мере необходимости, чтобы оставаться синхронизированным с вращением Земли, добавляя или вычитая високосные секунды³. В результате время UTC одинаково во всем мире, независимо от местного времени в разных часовых поясах.

Время UTC однозначно, оно не повторяется.

Timezone: Часовой пояс относится к региону на земном шаре, где все часы имеют одинаковое смещение от всемирного координированного времени (UTC). Это важно, поскольку влияет на местное время в различных частях мира.

Offset: Смещение относится к определенной продолжительности времени, которая либо добавляется, либо вычитается из Всемирного координированного времени (UTC) для получения местного времени в определенном часовом поясе. Это важно, поскольку влияет на местное время в разных частях света. Мы можем создать смещение, используя класс timedelta из модуля datetime

from datetime import timedelta

offset = timedelta(hours=1)
dt2 = dt + offset

Распечатав dt2, вы получите следующую информацию: datetime.datetime(2023, 5, 4, 11, 30, tzinfo=<DstTzInfo ‘Asia/Singapore’ LMT+6:55:00 STD>). Обратите внимание, что атрибут часа изменяется с 10 на 1 после добавления смещения.

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

Атрибуты и методы для объектов datetime, стандарт ISO 8601

Класс datetime имеет несколько важных атрибутов, которые обычно используются при манипулировании datetime. Это year, month, day, hour, minute, second, microsecond и tzinfo. Из нашего примера,

print(dt.year) #2023
print(dt.month) #5 
print(dt.day) #4
print(dt.hour) #11
print(dt.minute) #30
print(dt.second) #0
print(dt.microsecond) #0
print(dt.tzinfo) #Asia/Singapore

Некоторые из основных методов включают date(), time(), replace(), isoformat(), isocalendar(), strftime(format). Погодите, а что такое формат ISO?

Формат календаря ISO — это стандарт, используемый во всем мире для представления даты и времени в формате, удобном для чтения компьютерными программами⁴. Формат состоит из особого синтаксиса, в котором даты представлены четырьмя цифрами года, двумя цифрами месяца и двумя цифрами дня (ГГГГ-ММ-ДД). Например, 1 января 2023 года будет представлено как «2023–01–01». Кроме того, он также может принимать более сложную информацию, такую как время и часовой пояс, как показано в коде ниже.

print(dt.isoformat())
#return '2023-05-04T10:30:00+06:55'

print(dt.isocalendar()) 
#return tuple of datetime.IsoCalendarDate(year=2023, week=18, weekday=4)

datetime.fromisoformat("2023-01-05")
#return datetime.datetime(2023, 1, 5, 0, 0)

datetime.fromisoformat('2011-11-04T00:05:23')
#return datetime.datetime(2011, 11, 4, 0, 5, 23)

datetime.fromisoformat('2011-11-04 00:05:23.283')
#return datetime.datetime(2011, 11, 4, 0, 5, 23, 283000)

datetime.fromisoformat('2011-11-04 00:05:23.283+00:00')
#return datetime.datetime(2011, 11, 4, 0, 5, 23, 283000, tzinfo=datetime.timezone.utc)

datetime.fromisoformat('2011-11-04T00:05:23+04:00')
#return datetime.datetime(2011, 11, 4, 0, 5, 23, tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))

Давайте углубимся в последнюю строку кода подробнее.

  • 2011-11-04: Компонент даты представляет 4 ноября 2011 года.
  • T: Символ-разделитель, указывающий начало компонента времени.
  • 00:05:23: Временная составляющая, представляющая 12:05:23 утра.
  • +04:00: Компонент смещения часового пояса, указывающий на 4-часовую разницу во времени со всемирным координированным временем (UTC) в положительном направлении (впереди от UTC).

Форматирование объектов datetime с использованием strftime (format) и синтаксический анализ строк для объектов datetime с использованием strptime (format)

В Python вы можете использовать метод strftime(format) для преобразования объектов datetime в строки. Вам просто нужно дать ему строку, которая сообщает, как вы хотите, чтобы строка выглядела. И наоборот, вы также можете анализировать строки в объекте datetime, используя метод strptime(input_string, input_format).

Строка формата может содержать комбинацию кодов формата и буквенных символов. Коды формата — это специальные последовательности символов (обозначаемые символом %), которые заменяются соответствующими значениями из объекта datetime. Буквенные символы включаются в результирующую строку как есть. Вот список кодов распространенных форматов из Руководства пользователя Python¹.

  • %Y: Год в виде четырехзначного числа.
  • %m: Месяц в виде десятичного числа, дополненного нулями (01–12).
  • %d: День месяца в виде десятичного числа, дополненного нулями (01–31).
  • %H: The hour as a zero-padded decimal number (00-23).
  • %M: Минуты в виде десятичного числа с нулями (00-59).
  • %S: Второе - десятичное число с дополнением к нулю (00-59).
  • %a: Сокращенное название дня недели (Вс, Пн, Вт и т. д.).
  • %A: Полное название дня недели (воскресенье, понедельник, вторник и т. д.).
  • %b: Сокращенное название месяца (Jan, Feb, Mar и т. д.).
  • %B: Полное название месяца (январь, февраль, март и т. д.).
  • %p: Обозначение AM/PM (AM или PM).
from datetime import datetime
import pytz

tz = pytz.timezone('Asia/Singapore')
dt = datetime(2023, 5, 4, 10, 30, tzinfo=tz)

# Format as YYYY-MM-DD
# Output: 2023-05-04
print(dt.strftime('%Y-%m-%d'))

# Format as MM/DD/YYYY
# Output: 05/04/2023
print(dt.strftime('%m/%d/%Y'))   

# Format as Weekday, Month DD, YYYY HH:MM PM/AM
# Output: Thursday, May 04, 2023 10:30 AM
print(dt.strftime('%A, %B %d, %Y %I:%M %p'))

# .strptime() converts string to datetime object
# Output: 2023-05-04 20:30:45 with type datetime.datetime
dt_parsed = datetime.strptime("2023-05-04 20:30:45", '%Y-%m-%d %H:%M:%S')
print(dt_parsed)

# Another example of .strptime()
# Output: 2022-05-05 12:30:00
input_str = '5 May 2022 12:30 PM'
input_format = '%d %B %Y %I:%M %p'
dt = datetime.strptime(input_str, input_format)

Объекты timedelta

Объект timedelta в Python представляет продолжительность или разницу между двумя датами или временем. Его можно использовать для выполнения арифметических действий с объектами даты и времени, таких как добавление или вычитание временных интервалов или вычисление разницы между двумя объектами datetime¹.

Чтобы создать объект timedelta, вы можете использовать конструктор datetime.timedelta(), который принимает один или несколько аргументов для указания продолжительности. Аргументы могут быть целыми числами или числами с плавающей запятой, представляющими количество дней, секунд, микросекунд или их комбинацию. Например, timedelta(days=1, hours=3) создает объект timedelta, который представляет один день и три часа. С объектами timedelta можно выполнять такие арифметические операции, как сложение, вычитание, умножение и деление, а также их можно сравнивать с помощью операторов сравнения. Например,

from datetime import timedelta

delta_1 = timedelta(days=5, seconds=55, microseconds=555)
delta_2 = timedelta(days=1, seconds=11, microseconds=111)

print(delta_1.total_seconds()) #return 432055.000555
print(delta_1 - delta_2) #return 4 days, 0:00:44.000444
print(delta_1 > delta_2) #return True
print(delta_1 * 2) #return datetime.timedelta(days=10, seconds=110, microseconds=1110)
print(delta_1 / 2) #datetime.timedelta(days=2, seconds=43227, microseconds=500278)

Отметка времени POSIX

Временная метка POSIX, также называемая временной меткой Unix или временной меткой эпохи, представляет собой способ представления времени в виде одного целочисленного значения, которое можно легко сравнивать и манипулировать⁵. Он широко используется в компьютерных системах и языках программирования, таких как Python. Он представляет момент времени как количество секунд с 1 января 1970 года, 00:00:00 UTC, которое известно как время эпохи Unix. Это полезно для хранения и управления датами и временем в компьютерных системах, поскольку на него не влияют часовые пояса и летнее время (DST).

from datetime import datetime

# create a datetime object for a specific date and time
dt1 = datetime(2023, 5, 4, 10, 30, 0)
dt2 = datetime(2023, 5, 4, 11, 30, 0)

# convert the datetime object to a POSIX timestamp
timestamp1 = dt1.timestamp()
timestamp2 = dt2.timestamp()

print(timestamp1)  # output: 1683171000.0
print(timestamp2)  # output: 1683174600.0
print(timestamp2 - timestamp1)  # output: 3600.0

Обратите внимание, что разница между отметками времени составляет 3600 секунд, что равно интервалу в один час.

Точно так же мы можем преобразовать POSIX Timestamp в объект datetime.

from datetime import datetime

# create a POSIX timestamp for a specific date and time
timestamp = 1680658200.0

# convert the POSIX timestamp to a datetime object
dt = datetime.fromtimestamp(timestamp)

print(dt)  # output: 2023-04-05 08:30:00

Pandas, .dt accessor и datetime64[ns]

Тип данных datetime64[ns] — это тип данных, который представляет дату и время с точностью до наносекунд. Он является частью библиотеки NumPy в Python и похож на модуль datetime, но лучше работает с большими наборами данных о дате и времени. Это делает его более эффективным при работе с большими наборами данных, особенно в сочетании с другими функциями NumPy для обработки массивов и матриц.

При работе с библиотекой Pandas datetime64[ns] — отличный тип данных для работы, поскольку он позволяет нам получить доступ к мощному атрибуту dt для работы с объектом datetime. Обратите внимание, что этот атрибут недоступен для объекта pd.Timestamp, поэтому рекомендуется преобразовать ваш тип данных в datetime64[ns] для простоты манипулирования объектом datetime. Давайте начнем. Мы будем импортировать случайную метку времени с 2 городами (Бангкок/Сингапур) из 500 записей из CSV-файла. По умолчанию тип данных будет str. Этот раздел и стиль кодирования здесь вдохновлены книгой Effective Pandas⁶.

random_timestamp = pd.read_csv("random_timestamp.csv")
random_timestamp

К вашему сведению, время смещения для Бангкока — GMT+7, тогда как время смещения для Сингапура — GMT+8. Наша цель - преобразовать все время в сингапурское время. Работа с объектом datetime в Pandas…

#Creating the offset
offset = np.where(random_timestamp.country == "Bangkok", "+07:00", "+08:00")
offset

#Convert data type using pd.to_datetime, groupby offset, convert to SG time
(pd
 .to_datetime(random_timestamp.timestamp)
 .groupby(offset)
 .transform(lambda s: s.dt.tz_localize(s.name)
                       .dt.tz_convert('Asia/Singapore'))
)

Если вас смущает последняя операция метода, вот разбивка: во-первых, предполагается, что серия datetime или индекс не зависят от часового пояса, т.е. к ним не привязана никакая информация о часовом поясе.

  • Метод .dt.tz_localize() используется для присоединения часового пояса к ряду или индексу даты и времени, что эффективно делает его осведомленным о часовом поясе.
  • Метод принимает единственный аргумент, который является часовым поясом, для которого должны быть локализованы серия или индекс datetime.
  • После присоединения часового пояса к ряду или индексу datetime вы можете выполнять операции с datetime, для которых требуется информация о часовом поясе, например преобразование столбца в определенный часовой пояс (например, Сингапур).
Левый и правый вывод: без и с преобразованием в определенный Timezone
Левый и правый вывод: без и с преобразованием в определенный Timezone

Аксессор .dt позволяет нам получать информацию о datetime, как показано ниже.

offset = np.where(random_timestamp.country == "Bangkok", "+07:00", "+08:00")
offset

(random_timestamp
 .assign(sg_time = (pd
                     .to_datetime(random_timestamp.timestamp)
                     .groupby(offset)
                     .transform(lambda s: s.dt.tz_localize(s.name)
                                           .dt.tz_convert('Asia/Singapore'))),
         sg_hour = lambda df_: df_.sg_time.dt.hour,
         sg_minute = lambda df_: df_.sg_time.dt.minute,
         sg_second = lambda df_: df_.sg_time.dt.second,
         sg_weekday = lambda df_: df_.sg_time.dt.weekday,
         sg_weekofyear = lambda df_: df_.sg_time.dt.isocalendar().week,
         sg_strftime = lambda df_: df_.sg_time.dt.strftime('%A, %B %d, %Y %I:%M %p'))
)

Дата как индекс, метод .resample(), .agg(), .transform()

Этот раздел и стиль кодирования здесь вдохновлены книгой Effective Pandas⁶. Представьте, что у нас есть набор данных о температуре в несколько моментов времени дня, как показано ниже.

Мы хотели бы выполнить агрегацию данных, чтобы узнать минимальную, максимальную и среднюю температуру дня. Мы можем добиться этого, установив индекс DataFrame для столбца, содержащего объект datetime, затем используя метод resample и указав частоту агрегирования.

(temp_record
 .set_index("timestamp")
 .resample('D')
 .agg(['min', 'max', 'mean'])
 .round(1)
)
.agg() суммирует и сжимает записи DataFrame.
.agg() суммирует и сжимает записи DataFrame.

Если мы хотим сохранить количество строк, а не сократить его до 7 дней, мы можем использовать метод transform() вместо agg(). Однако обратите внимание, что функция transform() не может принимать список методов агрегации, а ограничена только одним методом агрегации за раз.

(temp_record
 .set_index("timestamp")
 .resample('D')
 .transform('min')
 .round(1)
)
.transform() сохраняет все записи DataFrame
.transform() сохраняет все записи DataFrame

Послесловие

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

Предлагаем вам также ознакомится с нашей статьей об анализе временных рядов и их визуализации.

Использованная литература:

  1. Документы Python: https://docs.python.org/3/library/datetime.html#timezone-objects
  2. Национальный центр ураганов и Центрально-Тихоокеанский центр ураганов. Что такое время UTC или GMT? https://www.nhc.noaa.gov/aboututc.shtml#:~:text=Prior%20to%201972%2C%20this%20time,%22%20or%20%22Zulu%20Time%22.
  3. Национальный институт стандартов и технологий. Что такое время USNO или UTC (USNO)? https://www.nist.gov/pml/time-and-frequency-division/nist-time-frequently-asked-questions-faq#:~:text=USNO%20has%20an%20ensemble%20of,scale%20called%20UTC(USNO).
  4. Международная Организация Стандартизации. Формат даты и времени ISO 8601. https://www.iso.org/iso-8601-date-and-time-format.html
  5. UNIX Time. https://unixtime.org/
  6. Effective Pandas by Matt Harrison: https://store.metasnake.com/effective-pandas-book

Источник:

#Python #Pandas #Data Science
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу