Преобразование строк в datetime в Python

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

Вступление

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

К счастью, Python поставляется со встроенным модулем datetime для работы с датой и временем. Как вы, наверное, догадались, в нем есть различные функции для управления датой и временем. Используя этот модуль, мы можем легко проанализировать любую строку даты и времени и преобразовать ее в объект datetime

Преобразование строк с использованием datetime

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

Например, следующий код напечатает текущую дату и время:

 import datetime 
 
 print ('Current date/time: {}'.format(datetime.datetime.now())) 

Запуск этого кода напечатает что-то похожее на это:

 $ python3 datetime-print-1.py 
 Current date/time: 2018-06-29 08:15:27.243860 

Если пользовательское форматирование не задано, используется строковый формат по умолчанию, т.е. формат для «2018-06-29 08: 15: 27.243860» находится в формате ISO 8601 (ГГГГ-ММ-ДДТЧЧ: ММ: СС.мммммм). Если наша входная строка для создания datetime имеет тот же формат ISO 8601, мы можем легко преобразовать ее в объект datetime

Давайте посмотрим на код ниже:

 import datetime 
 
 date_time_str = '2018-06-29 08:15:27.243860' 
 date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S.%f') 
 
 print('Date:', date_time_obj.date()) 
 print('Time:', date_time_obj.time()) 
 print('Date-time:', date_time_obj) 

Запустив его, он напечатает дату, время и дату-время:

 $ python3 datetime-print-2.py 
 Date: 2018-06-29 
 Time: 08:15:27.243860 
 Date-time: 2018-06-29 08:15:27.243860 

В этом примере мы используем новый метод под названием strptime . Этот метод принимает два аргумента: первый - это строковое представление даты и времени, а второй - формат входной строки. Указание формата, подобного этому, значительно ускоряет синтаксический анализ, поскольку datetime не нужно пытаться интерпретировать формат самостоятельно, что намного дороже в вычислительном отношении. Возвращаемое значение имеет тип datetime .

В нашем примере "2018-06-29 08:15:27.243860" - это входная строка, а "%Y-%m-%d %H:%M:%S.%f" - это формат нашей строки даты. Возвращаемое datetime сохраняется в переменной date_time_obj Поскольку это datetime , мы можем вызывать date() и time() непосредственно на нем. Как видно из выходных данных, он печатает часть «дата» и «время» входной строки.

Вам может быть интересно, что означает формат "%Y-%m-%d %H:%M:%S.%f" . Они известны как токены формата . Каждый токен представляет собой отдельную часть даты и времени, например день, месяц, год и т. Д. Ознакомьтесь с документацией strptime , чтобы найти список всех различных типов кода формата, поддерживаемых в Python. Для быстрого ознакомления вот что мы используем в приведенном выше коде:

  • %Y : год (4 цифры)
  • %m : месяц
  • %d : день месяца
  • %H : час (24 часа)
  • %M : минуты
  • %S : секунды
  • %f : микросекунды

Ожидается, что все эти токены, кроме года, будут заполнены нулями.

Итак, если известен формат строки, ее можно легко strptime datetime с помощью strptime. Приведу еще один нетривиальный пример:

 import datetime 
 
 date_time_str = 'Jun 28 2018 7:40AM' 
 date_time_obj = datetime.datetime.strptime(date_time_str, '%b %d %Y %I:%M%p') 
 
 print('Date:', date_time_obj.date()) 
 print('Time:', date_time_obj.time()) 
 print('Date-time:', date_time_obj) 

Из следующего вывода вы можете видеть, что строка была успешно проанализирована, поскольку она правильно распечатывается datetime здесь:

 $ python3 datetime-print-3.py 
 Date: 2018-06-28 
 Time: 07:40:00 
 Date-time: 2018-06-28 07:40:00 

Вот еще несколько примеров часто используемых форматов времени и токенов, используемых для синтаксического анализа:

 "Jun 28 2018 at 7:40AM" -> "%b %d %Y at %I:%M%p" 
 "September 18, 2017, 22:19:55" -> "%B %d, %Y, %H:%M:%S" 
 "Sun,05/12/99,12:30PM" -> "%a,%d/%m/%y,%I:%M%p" 
 "Mon, 21 March, 2015" -> "%a, %d %B, %Y" 
 "2018-03-12T10:12:45Z" -> "%Y-%m-%dT%H:%M:%SZ" 

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

Работа с часовыми поясами и датой и временем

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

 import datetime as dt 
 
 dtime = dt.datetime.now() 
 
 print(dtime) 
 print(dtime.tzinfo) 

Этот код напечатает:

 $ python3 datetime-tzinfo-1.py 
 2018-06-29 22:16:36.132767 
 None 

Вывод tzinfo - None поскольку это наивный объект datetime Для преобразования часового пояса для Python доступна pytz Вы можете установить его, как описано в этих инструкциях . Теперь давайте воспользуемся pytz чтобы преобразовать указанную выше метку времени в UTC .

 import datetime as dt 
 import pytz 
 
 dtime = dt.datetime.now(pytz.utc) 
 
 print(dtime) 
 print(dtime.tzinfo) 

Выход:

 $ python3 datetime-tzinfo-2.py 
 2018-06-29 17:08:00.586525+00:00 
 UTC 

+00:00 - разница между отображаемым временем и временем UTC. В этом примере значение tzinfo с UTC, отсюда смещение 00:00 В этом случае datetime является объектом с учетом часового пояса .

Точно так же мы можем преобразовать строки даты и времени в любой другой часовой пояс. Например, мы можем преобразовать строку «2018-06-29 17: 08: 00.586525 + 00: 00» в часовой пояс «America / New_York», как показано ниже:

 import datetime as dt 
 import pytz 
 
 date_time_str = '2018-06-29 17:08:00' 
 date_time_obj = dt.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S') 
 
 timezone = pytz.timezone('America/New_York') 
 timezone_date_time_obj = timezone.localize(date_time_obj) 
 
 print(timezone_date_time_obj) 
 print(timezone_date_time_obj.tzinfo) 

Выход:

 $ python3 datetime-tzinfo-3.py 
 2018-06-29 17:08:00-04:00 
 America/New_York 

Сначала мы преобразовали строку в объект datetime date_time_obj . Затем мы преобразовали его в объект datetime timezone_date_time_obj . Поскольку мы установили часовой пояс как «America / New_York», время вывода показывает, что он на 4 часа отстает от времени UTC. Вы можете проверить эту страницу Википедии, чтобы найти полный список доступных часовых поясов.

Преобразование часовых поясов

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

 import datetime as dt 
 import pytz 
 
 timezone_nw = pytz.timezone('America/New_York') 
 nw_datetime_obj = dt.datetime.now(timezone_nw) 
 
 timezone_london = pytz.timezone('Europe/London') 
 london_datetime_obj = nw_datetime_obj.astimezone(timezone_london) 
 
 
 print('America/New_York:', nw_datetime_obj) 
 print('Europe/London:', london_datetime_obj) 

Сначала мы создали один объект datetime с текущим временем и установили его как часовой пояс «America / New_York». Затем, используя метод astimezone() , мы преобразовали это datetime в часовой пояс «Европа / Лондон». Оба datetime s будут печатать разные значения, например:

 $ python3 datetime-tzinfo-4.py 
 America/New_York: 2018-06-29 22:21:41.349491-04:00 
 Europe/London: 2018-06-30 03:21:41.349491+01:00 

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

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

Модуль Python datetime может преобразовывать все разные типы строк в объект datetime Но основная проблема в том, что для этого вам нужно создать соответствующую строку кода форматирования, strptime может понять strptime. Создание этой строки требует времени и затрудняет чтение кода. Вместо этого мы можем использовать другие сторонние библиотеки, чтобы упростить задачу.

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

Давайте рассмотрим некоторые из этих библиотек в следующих разделах.

dateutil

Модуль dateutil является расширением модуля datetime Одно из преимуществ состоит в том, что нам не нужно передавать код синтаксического анализа для синтаксического анализа строки. Например:

 from dateutil.parser import parse 
 
 datetime = parse('2018-06-29 22:21:41') 
 
 print(datetime) 

Этот parse функция автоматически разобрать строку и сохранить ее в datetime и datetime переменной. Парсинг выполняется автоматически. Вам не нужно указывать какую-либо строку формата. Попробуем разобрать разные типы строк с помощью dateutil :

 from dateutil.parser import parse 
 
 date_array = [ 
 '2018-06-29 08:15:27.243860', 
 'Jun 28 2018 7:40AM', 
 'Jun 28 2018 at 7:40AM', 
 'September 18, 2017, 22:19:55', 
 'Sun, 05/12/1999, 12:30PM', 
 'Mon, 21 March, 2015', 
 '2018-03-12T10:12:45Z', 
 '2018-06-29 17:08:00.586525+00:00', 
 '2018-06-29 17:08:00.586525+05:00', 
 'Tuesday , 6th September, 2017 at 4:30pm' 
 ] 
 
 for date in date_array: 
 print('Parsing: ' + date) 
 dt = parse(date) 
 print(dt.date()) 
 print(dt.time()) 
 print(dt.tzinfo) 
 print('\n') 

Выход:

 $ python3 dateutil-1.py 
 Parsing: 2018-06-29 08:15:27.243860 
 2018-06-29 
 08:15:27.243860 
 None 
 
 Parsing: Jun 28 2018 7:40AM 
 2018-06-28 
 07:40:00 
 None 
 
 Parsing: Jun 28 2018 at 7:40AM 
 2018-06-28 
 07:40:00 
 None 
 
 Parsing: September 18, 2017, 22:19:55 
 2017-09-18 
 22:19:55 
 None 
 
 Parsing: Sun, 05/12/1999, 12:30PM 
 1999-05-12 
 12:30:00 
 None 
 
 Parsing: Mon, 21 March, 2015 
 2015-03-21 
 00:00:00 
 None 
 
 Parsing: 2018-03-12T10:12:45Z 
 2018-03-12 
 10:12:45 
 tzutc() 
 
 Parsing: 2018-06-29 17:08:00.586525+00:00 
 2018-06-29 
 17:08:00.586525 
 tzutc() 
 
 Parsing: 2018-06-29 17:08:00.586525+05:00 
 2018-06-29 
 17:08:00.586525 
 tzoffset(None, 18000) 
 
 Parsing: Tuesday , 6th September, 2017 at 4:30pm 
 2017-09-06 
 16:30:00 
 None 

Как видите, практически любой тип строки можно легко проанализировать с dateutil модуля dateutil.

Хотя это удобно, вспомните, как было сказано ранее, что необходимость предсказывать формат делает код намного медленнее, поэтому, если ваш код требует высокой производительности, это может быть неправильным подходом для вашего приложения.

майя

Maya также упрощает синтаксический анализ строки и изменение часовых поясов. Здесь показаны несколько простых примеров:

 import maya 
 
 dt = maya.parse('2018-04-29T17:45:25Z').datetime() 
 print(dt.date()) 
 print(dt.time()) 
 print(dt.tzinfo) 

Выход:

 $ python3 maya-1.py 
 2018-04-29 
 17:45:25 
 UTC 

Для преобразования времени в другой часовой пояс:

 import maya 
 
 dt = maya.parse('2018-04-29T17:45:25Z').datetime(to_timezone='America/New_York', naive=False) 
 print(dt.date()) 
 print(dt.time()) 
 print(dt.tzinfo) 

Выход:

 $ python3 maya-2.py 
 2018-04-29 
 13:45:25 
 America/New_York 

Разве не так просто использовать? Давайте попробуем maya с тем же набором строк, который мы использовали с dateutil :

 import maya 
 
 date_array = [ 
 '2018-06-29 08:15:27.243860', 
 'Jun 28 2018 7:40AM', 
 'Jun 28 2018 at 7:40AM', 
 'September 18, 2017, 22:19:55', 
 'Sun, 05/12/1999, 12:30PM', 
 'Mon, 21 March, 2015', 
 '2018-03-12T10:12:45Z', 
 '2018-06-29 17:08:00.586525+00:00', 
 '2018-06-29 17:08:00.586525+05:00', 
 'Tuesday , 6th September, 2017 at 4:30pm' 
 ] 
 
 for date in date_array: 
 print('Parsing: ' + date) 
 dt = maya.parse(date).datetime() 
 print(dt) 
 print(dt.date()) 
 print(dt.time()) 
 print(dt.tzinfo) 

Выход:

 $ python3 maya-3.py 
 Parsing: 2018-06-29 08:15:27.243860 
 2018-06-29 08:15:27.243860+00:00 
 2018-06-29 
 08:15:27.243860 
 UTC 
 
 Parsing: Jun 28 2018 7:40AM 
 2018-06-28 07:40:00+00:00 
 2018-06-28 
 07:40:00 
 UTC 
 
 Parsing: Jun 28 2018 at 7:40AM 
 2018-06-28 07:40:00+00:00 
 2018-06-28 
 07:40:00 
 UTC 
 
 Parsing: September 18, 2017, 22:19:55 
 2017-09-18 22:19:55+00:00 
 2017-09-18 
 22:19:55 
 UTC 
 
 Parsing: Sun, 05/12/1999, 12:30PM 
 1999-05-12 12:30:00+00:00 
 1999-05-12 
 12:30:00 
 UTC 
 
 Parsing: Mon, 21 March, 2015 
 2015-03-21 00:00:00+00:00 
 2015-03-21 
 00:00:00 
 UTC 
 
 Parsing: 2018-03-12T10:12:45Z 
 2018-03-12 10:12:45+00:00 
 2018-03-12 
 10:12:45 
 UTC 
 
 Parsing: 2018-06-29 17:08:00.586525+00:00 
 2018-06-29 17:08:00.586525+00:00 
 2018-06-29 
 17:08:00.586525 
 UTC 
 
 Parsing: 2018-06-29 17:08:00.586525+05:00 
 2018-06-29 12:08:00.586525+00:00 
 2018-06-29 
 12:08:00.586525 
 UTC 
 
 Parsing: Tuesday , 6th September, 2017 at 4:30pm 
 2017-09-06 16:30:00+00:00 
 2017-09-06 
 16:30:00 
 UTC 

Как видите, все форматы даты были успешно проанализированы.

Но вы заметили разницу? Если мы не предоставляем информацию о часовом поясе, он автоматически преобразует ее в UTC. Итак, важно отметить, что мы должны предоставить параметры to_timezone и naive если время не в формате UTC.

Стрела

Arrow - еще одна библиотека для работы с datetime в Python. И, как и раньше с maya , он также автоматически определяет формат даты и времени. После интерпретации он возвращает объект datetime Python из объекта arrow

Давайте попробуем это с той же примерной строкой, которую мы использовали для maya :

 import arrow 
 
 dt = arrow.get('2018-04-29T17:45:25Z') 
 print(dt.date()) 
 print(dt.time()) 
 print(dt.tzinfo) 

Выход:

 $ python3 arrow-1.py 
 2018-04-29 
 17:45:25 
 tzutc() 

А вот как можно использовать arrow для преобразования часовых поясов с помощью метода to

 import arrow 
 
 dt = arrow.get('2018-04-29T17:45:25Z').to('America/New_York') 
 print(dt) 
 print(dt.date()) 
 print(dt.time()) 

Выход:

 $ python3 arrow-2.py 
 2018-04-29T13:45:25-04:00 
 2018-04-29 
 13:45:25 

Как видите, строка даты и времени преобразована в регион "Америка / Нью-Йорк".

Теперь давайте снова воспользуемся тем же набором строк, который мы использовали выше:

 import arrow 
 
 date_array = [ 
 '2018-06-29 08:15:27.243860', 
 #'Jun 28 2018 7:40AM', 
 #'Jun 28 2018 at 7:40AM', 
 #'September 18, 2017, 22:19:55', 
 #'Sun, 05/12/1999, 12:30PM', 
 #'Mon, 21 March, 2015', 
 '2018-03-12T10:12:45Z', 
 '2018-06-29 17:08:00.586525+00:00', 
 '2018-06-29 17:08:00.586525+05:00', 
 #'Tuesday , 6th September, 2017 at 4:30pm' 
 ] 
 
 for date in date_array: 
 dt = arrow.get(date) 
 print('Parsing: ' + date) 
 print(dt) 
 print(dt.date()) 
 print(dt.time()) 
 print(dt.tzinfo) 

Этот код завершится ошибкой для закомментированных строк даты и времени, что составляет более половины наших примеров. Вывод для других строк будет:

 $ python3 arrow-3.py 
 Parsing: 2018-06-29 08:15:27.243860 
 2018-06-29T08:15:27.243860+00:00 
 2018-06-29 
 08:15:27.243860 
 tzutc() 
 
 Parsing: 2018-03-12T10:12:45Z 
 2018-03-12T10:12:45+00:00 
 2018-03-12 
 10:12:45 
 tzutc() 
 
 Parsing: 2018-06-29 17:08:00.586525+00:00 
 2018-06-29T17:08:00.586525+00:00 
 2018-06-29 
 17:08:00.586525 
 tzoffset(None, 0) 
 
 Parsing: 2018-06-29 17:08:00.586525+05:00 
 2018-06-29T17:08:00.586525+05:00 
 2018-06-29 
 17:08:00.586525 
 tzoffset(None, 18000) 

Чтобы правильно проанализировать строки даты и времени, которые я закомментировал, вам необходимо передать соответствующие токены формата, чтобы дать библиотеке подсказки относительно того, как их анализировать. Например, «MMM» для названия месяцев, например «Jan, Feb, Mar» и т. Д. Вы можете проверить это руководство для всех доступных токенов.

Заключение

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

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

Еще одна проблема, с которой мы сталкиваемся, - это часовые пояса. Лучший способ справиться с ними - всегда сохранять время в базе данных в формате UTC, а затем при необходимости преобразовывать его в местный часовой пояс пользователя.

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

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus