Python Language
Дата и время
Поиск…
замечания
Python предоставляет встроенные методы и внешние библиотеки для создания, модификации, разбора и управления датами и временем.
Разбор строки в объекте datetime, посвященном часовому поясу
Python 3.2+ поддерживает формат %z
при разборе строки в объект datetime
.
UTC в форме
+HHMM
или-HHMM
(пустая строка, если объект наивен).
import datetime
dt = datetime.datetime.strptime("2016-04-15T08:27:18-0500", "%Y-%m-%dT%H:%M:%S%z")
Для других версий Python вы можете использовать внешнюю библиотеку, такую как dateutil
, которая dateutil
анализирует строку с dateutil
в объект datetime
.
import dateutil.parser
dt = 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 datetime
today = 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-15
Yesterday: 2016-04-14
Tomorrow: 2016-04-16
Difference between tomorrow and yesterday: 2 days, 0:00:00
Использование базовых объектов datetime
Модуль datetime содержит три основных типа объектов - дату, время и дату и время.
import datetime
# Date object
today = datetime.date.today()
new_year = datetime.date(2017, 01, 01) #datetime.date(2017, 1, 1)
# Time object
noon = datetime.time(12, 0, 0) #datetime.time(12, 0)
# Current datetime
now = datetime.datetime.now()
# Datetime object
millenium_turn = datetime.datetime(2000, 1, 1, 0, 0, 0) #datetime.datetime(2000, 1, 1, 0, 0)
Арифметические операции для этих объектов поддерживаются только внутри одного и того же типа данных, и выполнение простой арифметики с экземплярами разных типов приведет к типу TypeError.
# subtraction of noon from today
noon-today
Traceback (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 instead
print('Time since the millenium at midnight: ',
datetime.datetime(today.year, today.month, today.day) - millenium_turn)
# Or this
print('Time since the millenium at noon: ',
datetime.datetime.combine(today, noon) - millenium_turn)
Итерация по датам
Иногда вы хотите перебирать диапазон дат от даты начала до некоторой даты окончания. Вы можете сделать это с использованием библиотеки datetime
и объекта timedelta
:
import datetime
# The size of each step in days
day_delta = datetime.timedelta(days=1)
start_date = datetime.date.today()
end_date = start_date + 7*day_delta
for i in range((end_date - start_date).days):
print(start_date + i*day_delta)
Что производит:
2016-07-21
2016-07-22
2016-07-23
2016-07-24
2016-07-25
2016-07-26
2016-07-27
Разбор строки с коротким именем часового пояса в объекте datetime, относящемся к часовому поясу
Используя библиотеку dateutil
как в предыдущем примере, при разборе временных меток времени , можно также разобрать временные метки с указанным «коротким» именем часового пояса.
Для дат, отформатированных с короткими названиями зон или аббревиатурами, которые обычно неоднозначны (например, КНТ, которая может быть Центральным стандартным временем, Стандартным временем в Китае, Стандартным временем Кубы и т. Д. - здесь можно найти) или не обязательно доступна в стандартной базе данных , необходимо указать отображение между аббревиатурой часового пояса и объектом tzinfo
.
from dateutil import tz
from dateutil.parser import parse
ET = 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 parse
import pytz
EST = 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
и (необязательный) name:
from datetime import datetime, timedelta, timezone
JST = timezone(timedelta(hours=+9))
dt = datetime(2015, 1, 1, 12, 0, 0, tzinfo=JST)
print(dt)
# 2015-01-01 12:00:00+09:00
print(dt.tzname())
# UTC+09:00
dt = 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
указано в секундах:
from datetime import datetime, timedelta
from dateutil import tz
JST = tz.tzoffset('JST', 9 * 3600) # 3600 seconds per hour
dt = datetime(2015, 1, 1, 12, 0, tzinfo=JST)
print(dt)
# 2015-01-01 12:00:00+09:00
print(dt.tzname)
# 'JST'
Зоны с летним временем
Для зон с летним временем стандартные стандартные библиотеки python не предоставляют стандартный класс, поэтому необходимо использовать стороннюю библиотеку. pytz
и dateutil
популярные библиотеки , обеспечивающие классы часовых поясов.
Помимо статических часовых поясов, dateutil
предоставляет классы часовых поясов, которые используют летнее время (см. Документацию для модуля tz
). Вы можете использовать метод tz.gettz()
для получения объекта часового пояса, который затем может быть передан непосредственно конструктору datetime
:
from datetime import datetime
from dateutil import tz
local = tz.gettz() # Local time
PT = tz.gettz('US/Pacific') # Pacific time
dt_l = datetime(2015, 1, 1, 12, tzinfo=local) # I am in EST
dt_pst = datetime(2015, 1, 1, 12, tzinfo=PT)
dt_pdt = datetime(2015, 7, 1, 12, tzinfo=PT) # DST is handled automatically
print(dt_l)
# 2015-01-01 12:00:00-05:00
print(dt_pst)
# 2015-01-01 12:00:00-08:00
print(dt_pdt)
# 2015-07-01 12:00:00-07:00
ПРЕДУПРЕЖДЕНИЕ . Начиная с версии 2.5.3, dateutil
обрабатывает неоднозначные даты и всегда будет по умолчанию для более поздней даты. dateutil
построить объект с dateutil
представляющим, например, 2015-11-01 1:30 EDT-4
, так как это происходит во время перехода на летнее время.
При использовании pytz
все обработанные края обрабатываются должным образом, но часовые пояса pytz
не должны быть непосредственно привязаны к часовым поясам через конструктор. Вместо этого временная зона pytz
должна быть присоединена с использованием метода localize
часового пояса:
from datetime import datetime, timedelta
import pytz
PT = 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:00
print(dt_pdt)
# 2015-11-01 00:30:00-07:00
Имейте в виду, что если вы выполняете арифметику datetime в часовом поясе pytz
-aware, вы должны либо выполнить вычисления в формате UTC (если хотите абсолютное истекшее время), либо вы должны вызвать normalize()
для результата:
dt_new = dt_pdt + timedelta(hours=3) # This should be 2:30 AM PST
print(dt_new)
# 2015-11-01 03:30:00-07:00
dt_corrected = PT.normalize(dt_new)
print(dt_corrected)
# 2015-11-01 02:30:00-08:00
Нечеткий анализ времени и времени (извлечение даты и времени из текста)
Можно извлечь дату из текста, используя синтаксический анализатор dateutil
в режиме «нечеткого», в котором компоненты строки, не признанной как часть даты, игнорируются.
from dateutil.parser import parse
dt = 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 datetime
from dateutil import tz
utc = 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.
Разбор произвольной временной метки 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'
Но эти 2 формы нуждаются в другом формате для strptime
. Кроме того, strptime' does not support at all parsing minute timezones that have a
: in it, thus
2016-07-22 09: 25: 59 + 0300 can be parsed, but the standard format
2016-07-22 09:25:59 +03: 00` не может.
Существует библиотека с одним файлом, называемая iso8601
которая правильно анализирует временные метки ISO 8601 и только их.
Он поддерживает дроби и часовые пояса, а T
разделитель - с одной функцией:
import iso8601
iso8601.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
, тогда те временные метки, которые не имеют явного часового пояса, возвращаются вместо наивных datetimes:
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>)
Преобразование временной метки в дату и время
Модуль datetime
может преобразовать timestamp
POSIX в объект datetime
ИТЦ.
Эпоха - 1 января 1970 года в полночь.
import time
from datetime import datetime
seconds_since_epoch=time.time() #1469182681.709
utc_date=datetime.utcfromtimestamp(seconds_since_epoch) #datetime.datetime(2016, 7, 22, 10, 18, 1, 709000)
Вычитание месяцев с даты точно
Использование модуля calendar
import calendar
from datetime import date
def 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 datetime
import dateutil.relativedelta
d = datetime.datetime.strptime("2013-03-31", "%Y-%m-%d")
d2 = d - dateutil.relativedelta.relativedelta(months=1) #datetime.datetime(2013, 2, 28, 0, 0)
Вычисление временных разниц
модуль timedelta
пригодится для вычисления различий между временами:
from datetime import datetime, timedelta
now = datetime.now()
then = datetime(2016, 5, 23) # datetime.datetime(2016, 05, 23, 0, 0, 0)
Указание времени является необязательным при создании нового объекта datetime
delta = now-then
delta
имеет тип timedelta
print(delta.days)
# 60
print(delta.seconds)
# 40826
Чтобы получить n день после и n дней до даты, мы могли бы использовать:
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 datetime
datetime.now().isoformat()
# Out: '2016-07-31T23:08:20.886783'
С часовым поясом, с микросекундами
from datetime import datetime
from dateutil.tz import tzlocal
datetime.now(tzlocal()).isoformat()
# Out: '2016-07-31T23:09:43.535074-07:00'
С часовым поясом, без микросекунд
from datetime import datetime
from dateutil.tz import tzlocal
datetime.now(tzlocal()).replace(microsecond=0).isoformat()
# Out: '2016-07-31T23:10:30-07:00'
См. ISO 8601 для получения дополнительной информации о формате ISO 8601.