Путешествие во времени стало проще: Полное руководство по 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
, для которых требуется информация о часовом поясе, например преобразование столбца в определенный часовой пояс (например, Сингапур).
Аксессор .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)
)
Если мы хотим сохранить количество строк, а не сократить его до 7 дней, мы можем использовать метод transform()
вместо agg()
. Однако обратите внимание, что функция transform()
не может принимать список методов агрегации, а ограничена только одним методом агрегации за раз.
(temp_record
.set_index("timestamp")
.resample('D')
.transform('min')
.round(1)
)
Послесловие
Понимание и управление объектами datetime
является важным навыком для любого аналитика данных или ученого. Освоив различные доступные классы и методы, вы сможете извлечь ценную информацию из своих данных и принимать обоснованные решения и манипулировать датой и временем в вашу пользу. Обещайте мне, что в следующий раз, когда вы столкнетесь с набором данных с датами и временем, не уклоняйтесь от него — примите его, и пусть начнется магия datetime
!
Предлагаем вам также ознакомится с нашей статьей об анализе временных рядов и их визуализации.
Использованная литература:
- Документы Python: https://docs.python.org/3/library/datetime.html#timezone-objects
- Национальный центр ураганов и Центрально-Тихоокеанский центр ураганов. Что такое время UTC или GMT? https://www.nhc.noaa.gov/aboututc.shtml#:~:text=Prior%20to%201972%2C%20this%20time,%22%20or%20%22Zulu%20Time%22.
- Национальный институт стандартов и технологий. Что такое время 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).
- Международная Организация Стандартизации. Формат даты и времени ISO 8601. https://www.iso.org/iso-8601-date-and-time-format.html
- UNIX Time. https://unixtime.org/
- Effective Pandas by Matt Harrison: https://store.metasnake.com/effective-pandas-book