Документация по Python

Работа с датой и временем в Python

В: Документация по Python

Введение

Примеры

Как спарсить строку в datetime с часовым поясом

Python 3.2+ поддерживает формат %z при разборе строки в объекте datetime.

UTC в форме +HHMM или -HHMM (пустая строка, если объект не содержит информации о временной зоне).

Python 3.x 3.2

import datetimedt = datetime.datetime.strptime("2016-04-15T08:27:18-0500", "%Y-%m-%dT%H:%M:%S%z") 


Для других версий Python можно использовать внешнюю библиотеку, такую ​​как dateutil, которая проанализирует текст в объект datetime.

import dateutil.parserdt = dateutil.parser.parse("2016-04-15T08:27:18-0500")

Теперь переменная dt представляет собой объект datetime со следующим значением:

datetime.datetime(2016, 4, 15, 8, 27, 18, tzinfo=tzoffset(None, -18000))


Простые арифметические операции с датами

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

import datetimetoday = datetime.date.today()print('Today:', today)yesterday = today - datetime.timedelta(days=1)print('Yesterday:', yesterday)tomorrow = today + datetime.timedelta(days=1)print('Tomorrow:', tomorrow)print('Time between tomorrow and yesterday:', tomorrow - yesterday)

Получится:

Today: 2016-04-15Yesterday: 2016-04-14Tomorrow: 2016-04-16Difference between tomorrow and yesterday: 2 days, 0:00:00


Использование базовых объектов

Модуль datetime содержит три основных типа объектов: отдельно дату, отдельно время и дату вместе со временем.

import datetime# Date objecttoday = datetime.date.today()new_year = datetime.date(2017, 01, 01) #datetime.date(2017, 1, 1)# Time objectnoon = datetime.time(12, 0, 0) #datetime.time(12, 0)# Current datetimenow = datetime.datetime.now()# Datetime objectmillenium_turn = datetime.datetime(2000, 1, 1, 0, 0, 0) #datetime.datetime(2000, 1, 1, 0, 0)

Арифметические операции для этих объектов поддерживаются только для одного и того же типа данных. Если выполнять арифметические действия с разными типами объектов, то это приведет к ошибке TypeError.

# subtraction of noon from todaynoon-todayTraceback (most recent call last):  File "<stdin>", line 1, in <module>TypeError: unsupported operand type(s) for -: 'datetime.time' and 'datetime.date'However, it is straightforward to convert between types.# Do this insteadprint('Time since the millenium at midnight:',      datetime.datetime(today.year, today.month, today.day) - millenium_turn)# Or thisprint('Time since the millenium at noon:',      datetime.datetime.combine(today, noon) - millenium_turn)

Итерация по датам

Если нужно перебрать диапазон дат от даты начала до некоторой даты окончания, то можно использовать библиотеку datetime и объект timedelta:

import datetime# The size of each step in daysday_delta = datetime.timedelta(days=1)start_date = datetime.date.today()end_date = start_date + 7*day_deltafor i in range((end_date - start_date).days):    print(start_date + i*day_delta)

Получится:

2016-07-212016-07-222016-07-232016-07-242016-07-252016-07-262016-07-27


Спарсить строку с двухбуквенным часовым поясом и перевести в UTC

Используя библиотеку dateutil можно парсить временные метки с коротким буквенным именем часового пояса.

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

Например, CST. Это может быть Центральным стандартным временем, Стандартным временем в Китае, Стандартным временем Кубы и т.д. Полный список можно посмотреть здесь.

from dateutil import tzfrom dateutil.parser import parseET = tz.gettz('US/Eastern')CT = tz.gettz('US/Central')MT = tz.gettz('US/Mountain')PT = tz.gettz('US/Pacific')us_tzinfos = {'CST': CT, 'CDT': CT,              'EST': ET, 'EDT': ET,              'MST': MT, 'MDT': MT,              'PST': PT, 'PDT': PT}dt_est = parse('2014-01-02 04:00:00 EST', tzinfos=us_tzinfos)dt_pst = parse('2016-03-11 16:00:00 PST', tzinfos=us_tzinfos)

Дальнейшие действия:

dt_est# datetime.datetime(2014, 1, 2, 4, 0, tzinfo=tzfile('/usr/share/zoneinfo/US/Eastern'))dt_pst# datetime.datetime(2016, 3, 11, 16, 0, tzinfo=tzfile('/usr/share/zoneinfo/US/Pacific'))

При использовании с этим методом часового пояса pytz — часовой пояс правильно не локализуется:

from dateutil.parser import parseimport pytzEST = pytz.timezone('America/New_York')dt = parse('2014-02-03 09:17:00 EST', tzinfos={'EST': EST})

Привязка часового пояса pytz к дате и времени:

dt.tzinfo # Will be in Local Mean Time!# <DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>

Если вы используете этот метод, вы должны повторно использовать localize для простых значений даты и времени:

dt_fixed = dt.tzinfo.localize(dt.replace(tzinfo=None))dt_fixed.tzinfo # Now it's EST.# <DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)


Создание даты и времени в разных часовых поясах

Все объекты datetime по умолчанию не относятся ни к одному часовому поясу. Чтобы привязать их к определенному часовому поясу — им нужно назначить объект tzinfo, который привязывает функцию даты и времени к стандарту UTC.

Пересчёт часовых поясов

Для часовых поясов, которые фиксировано смещаются относительно UTC, в Python 3.2+ в модуле datetime есть класс timezone в котором реализован tzinfo, принимающий параметры timedelta и имя (необязательно):

Python 3.x 3.2

from datetime import datetime, timedelta, timezoneJST = timezone(timedelta(hours=+9))dt = datetime(2015, 1, 1, 12, 0, 0, tzinfo=JST)print(dt)# 2015-01-01 12:00:00+09:00print(dt.tzname())# UTC+09:00dt = datetime(2015, 1, 1, 12, 0, 0, tzinfo=timezone(timedelta(hours=9), 'JST'))print(dt.tzname)# 'JST'

Для Python-версий ниже 3.2 необходимо использовать стороннюю библиотеку. Например, dateutil. dateutil предоставляет эквивалентный класс tzoffset, который (tzoffset с версии 2.5.3) принимает аргументы вида dateutil.tz.tzoffset(tzname, offset), где offset указано в секундах:

Python 3.x 3.2

Python 2.x 2.7

from datetime import datetime, timedeltafrom dateutil import tzJST = tz.tzoffset('JST', 9 * 3600) # 3600 seconds per hourdt = datetime(2015, 1, 1, 12, 0, tzinfo=JST)print(dt)# 2015-01-01 12:00:00+09:00print(dt.tzname)# 'JST'

Часовые пояса с переходом на летнее время

Для часовых зон с летним временем в стандартных библиотеках python нет стандартных классов. Поэтому нужно использовать стороннюю библиотеку. Есть pytz и dateutil — популярные библиотеки,  в которых представлены классы часовых поясов.

Помимо стандартных часовых поясов, в dateutil есть классы часовых поясов, в которых используется летнее время (см. Документацию для модуля tz ). Можете использовать метод tz.gettz() для получения объекта часового пояса, который затем можно передать непосредственно в datetime:

from datetime import datetimefrom dateutil import tzlocal = tz.gettz() # Local timePT = tz.gettz('US/Pacific') # Pacific timedt_l = datetime(2015, 1, 1, 12, tzinfo=local) # I am in ESTdt_pst = datetime(2015, 1, 1, 12, tzinfo=PT)dt_pdt = datetime(2015, 7, 1, 12, tzinfo=PT) # DST is handled automaticallyprint(dt_l)# 2015-01-01 12:00:00-05:00print(dt_pst)# 2015-01-01 12:00:00-08:00print(dt_pdt)# 2015-07-01 12:00:00-07:00


ВНИМАНИЕ. Начиная с версии 2.5.3, dateutil обрабатывает неоднозначные даты и всегда будет назначен по умолчанию для более поздней даты. Невозможно создать объект dateutil с текущим часовым поясом, например, 2015-11-01 1:30 EDT-4, так как это происходит во время перехода на летнее время.

В крайних случаях при использовании pytz это можно сделать вручную, но в pytz часовые пояса не должны быть непосредственно привязаны через конструктор. Вместо этого временная зона pytz должна быть присоединена к часовому поясу с использованием метода localize:

from datetime import datetime, timedeltaimport pytzPT = pytz.timezone('US/Pacific')dt_pst = PT.localize(datetime(2015, 1, 1, 12))dt_pdt = PT.localize(datetime(2015, 11, 1, 0, 30))print(dt_pst)# 2015-01-01 12:00:00-08:00print(dt_pdt)# 2015-11-01 00:30:00-07:00


Если вы рассчитываете дату и время в часовом поясе pytz — вы должны либо выполнить вычисления для UTC (чтобы получить абсолютное истекшее время), либо используйте normalize():

dt_new = dt_pdt + timedelta(hours=3) # This should be 2:30 AM PSTprint(dt_new)# 2015-11-01 03:30:00-07:00dt_corrected = PT.normalize(dt_new)print(dt_corrected)# 2015-11-01 02:30:00-08:00


Извлечение даты и времени из текста (неопределенный анализ даты и времени)

Можно извлечь дату из текста, используя синтаксический анализатор dateutil в режиме «fuzzy», в котором компоненты строки, не идентифицирующиеся как часть даты, игнорируются.


from dateutil.parser import parsedt = parse("Today is January 1, 2047 at 8:21:00AM", fuzzy=True)print(dt)

dt теперь является объектом datetime и вы увидите datetime.datetime(2047, 1, 1, 8, 21).

Переключение между часовыми поясами

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

from datetime import datetimefrom dateutil import tzutc = tz.tzutc()local = tz.tzlocal()utc_now = datetime.utcnow()utc_now # Not timezone-aware.utc_now = utc_now.replace(tzinfo=utc)utc_now # Timezone-aware.local_now = utc_now.astimezone(local)local_now # Converted to local time.

Спарсить произвольный timestamp в ISO 8601 с минимумом подключаемых библиотек

У Python ограниченная поддержка анализа временных меток ISO 8601. Для того, чтобы использовать strptime — вам нужно точно знать его формат. Сложность в том, что в datetime с временной меткой ISO 8601 есть 6-разрядная дробь:

str(datetime.datetime(2016, 7, 22, 9, 25, 59, 555555))# '2016-07-22 09:25:59.555555'


Если дробная часть равна 0, то она не выводится:

str(datetime.datetime(2016, 7, 22, 9, 25, 59, 0))# '2016-07-22 09:25:59'

Но для этих двух вариантов используется другой формат для strptime.Кроме того, strptime не поддерживает ни минуты, ни обозначения часовых поясов с минутами. Например, 2016-07-22 09: 25: 59 + 0300 проанализируется, а стандартный формат вида 2016-07-22 09:25:59 +03: 00 нет.

Существует библиотека из одного файла — iso8601, которая правильно анализирует только временные метки ISO 8601.

Он поддерживает дроби, часовые пояса и T разделитель внутри единственной функции:

import iso8601iso8601.parse_date('2016-07-22 09:25:59')# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<iso8601.Utc>)iso8601.parse_date('2016-07-22 09:25:59+03:00')# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<FixedOffset '+03:00' ...>)iso8601.parse_date('2016-07-22 09:25:59Z')# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<iso8601.Utc>)iso8601.parse_date('2016-07-22T09:25:59.000111+03:00')# datetime.datetime(2016, 7, 22, 9, 25, 59, 111, tzinfo=<FixedOffset '+03:00' ...>)

Если часовой пояс не установлен, значение iso8601.parse_date соответствует UTC. Зона по умолчанию может быть изменена с помощью ключевого слова default_zone. Если вместо значения по умолчанию передаётся None, то тогда те значения даты и времени, у которых нет определенного часового значения, устанавливаются вместо простых значений даты и времени:

iso8601.parse_date('2016-07-22T09:25:59', default_timezone=None)# datetime.datetime(2016, 7, 22, 9, 25, 59)iso8601.parse_date('2016-07-22T09:25:59Z', default_timezone=None)# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<iso8601.Utc>)

Преобразование timestamp в datetime

Модуль datetime может преобразовать метку POSIX timestamp в объект ITC datetime.

Эпоха: 1 января 1970 года, полночь.


import timefrom datetime import datetimeseconds_since_epoch=time.time()  #1469182681.709utc_date=datetime.utcfromtimestamp(seconds_since_epoch) # datetime.datetime(2016, 7, 22, 10, 18, 1, 709000)

Вычисление количества месяцев с даты

Использование модуля calendar

import calendarfrom datetime import datedef monthdelta(date, delta):    m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12    if not m: m = 12    d = min(date.day, calendar.monthrange(y, m)[1])    return date.replace(day=d,month=m, year=y)next_month = monthdelta(date.today(), 1) #datetime.date(2016, 10, 23)

Использование модуля dateutils

import datetimeimport dateutil.relativedeltad = datetime.datetime.strptime("2013-03-31", "%Y-%m-%d")d2 = d - dateutil.relativedelta.relativedelta(months=1)  #datetime.datetime(201)

Вычисление разницы во времени

Модуль timedelta пригодится для вычисления разницы во времени:


from datetime import datetime, timedeltanow = datetime.now()then = datetime(2016, 5, 23)     # datetime.datetime(2016, 05, 23, 0, 0, 0)

При создании нового объекта datetime указывать время необязательно.

delta = now - then


delta — это тип timedelta


print(delta.days)# 60print(delta.seconds)# 40826


Чтобы получить n дней после даты:

def get_n_days_after_date(date_format="%d %B %Y", add_days=120):    date_n_days_after = datetime.datetime.now() + timedelta(days=add_days)    return date_n_days_after.strftime(date_format)


Чтобы получить n дней до даты:

def get_n_days_before_date(self, date_format="%d %B %Y", days_before=120):        date_n_days_ago = datetime.datetime.now() - timedelta(days=days_before)        return date_n_days_ago.strftime(date_format)

Получение временной метки ISO 8601

Без часового пояса с микросекундами

from datetime import datetimedatetime.now().isoformat()# Out: '2016-07-31T23:08:20.886783'

С часовым поясом и с микросекундами

from datetime import datetimefrom dateutil.tz import tzlocaldatetime.now(tzlocal()).isoformat()# Out: '2016-07-31T23:09:43.535074-07:00'

С часовым поясом без микросекунд

from datetime import datetimefrom dateutil.tz import tzlocaldatetime.now(tzlocal()).replace(microsecond=0).isoformat()# Out: '2016-07-31T23:10:30-07:00'

Синтаксис

Параметры

Примечания

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

Еще от кодкамп
Замечательно! Вы успешно подписались.
Добро пожаловать обратно! Вы успешно вошли
Вы успешно подписались на кодкамп.
Срок действия вашей ссылки истек.
Ура! Проверьте свою электронную почту на наличие волшебной ссылки для входа.
Успех! Ваша платежная информация обновлена.
Ваша платежная информация не была обновлена.