Python strptime() и часовые пояса?

У меня есть CSV файл из резервной копии BlackBird IPD, созданный с использованием IPDDump. Строки даты/времени здесь выглядят примерно так (где EST - австралийская часовая зона):

Tue Jun 22 07:46:22 EST 2010

Мне нужно проанализировать эту дату в Python. Сначала я попытался использовать функцию strptime() из времени datettime.

>>> datetime.datetime.strptime('Tue Jun 22 12:10:20 2010 EST', '%a %b %d %H:%M:%S %Y %Z')

Однако по какой-то причине возвращаемый объект datetime, похоже, не связан с ним tzinfo.

Я прочитал эту страницу, который, по-видимому, datetime.strptime молча отбрасывает tzinfo, однако я проверил документацию, и я могу "t найти что-либо с этим документом здесь.

Мне удалось получить синтаксический анализ, используя стороннюю библиотеку Python, dateutil, однако мне все еще интересно, как как я неправильно использовал встроенный strptime()? Есть ли способ получить strptime(), чтобы хорошо играть с часовыми поясами?

Ответ 1

datetime модуль документации гласит:

Возвращает datetime, соответствующее date_string, проанализированный в соответствии с форматом. Это эквивалентно datetime(*(time.strptime(date_string, format)[0:6])).

Видите это [0:6]? Это получает вас (year, month, day, hour, minute, second). Ничего больше. Нет упоминания о часовых поясах.

Интересно, что [Win XP SP2, Python 2.6, 2.7] передача вашего примера в time.strptime не работает, но если вы удалите "% Z" и "EST", это сработает. Также работает "UTC" или "GMT" вместо "EST". "PST" и "MEZ" не работают. Непонятные.

Стоит отметить, что это было обновлено с версии 3.2, и в той же документации теперь также говорится следующее:

Когда директива% z предоставляется методу strptime(), будет создан осведомленный объект datetime. Для tzinfo результата будет задан экземпляр часового пояса.

Обратите внимание, что это не работает с% Z, поэтому важен случай. Смотрите следующий пример:

In [1]: from datetime import datetime

In [2]: start_time = datetime.strptime('2018-04-18-17-04-30-AEST','%Y-%m-%d-%H-%M-%S-%Z')

In [3]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: None

In [4]: start_time = datetime.strptime('2018-04-18-17-04-30-+1000','%Y-%m-%d-%H-%M-%S-%z')

In [5]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: UTC+10:00

Ответ 2

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

>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)

и т.д. Не имея дело с формальной бессмысленностью strptime()... просто бросайте дату на нее, и она делает правильную вещь.

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

Ответ 3

Строка времени аналогична формату времени в rfc 2822 (формат даты в электронной почте, заголовки http). Вы можете разобрать его, используя только stdlib:

>>> from email.utils import parsedate_tz
>>> parsedate_tz('Tue Jun 22 07:46:22 EST 2010')
(2010, 6, 22, 7, 46, 22, 0, 1, -1, -18000)

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

В этом формате EST семантически эквивалентен -0500. Хотя, как правило, сокращения часового пояса недостаточно для однозначного определения часового пояса.

Ответ 4

Столкнулся с этой точной проблемой.

Что я в итоге сделал:

# starting with date string
sdt = "20190901"
std_format = '%Y%m%d'

# create naive datetime object
from datetime import datetime
dt = datetime.strptime(sdt, sdt_format)

# extract the relevant date time items
dt_formatters = ['%Y','%m','%d']
dt_vals = tuple(map(lambda formatter: int(datetime.strftime(dt,formatter)), dt_formatters))

# set timezone
import pendulum
tz = pendulum.timezone('utc')

dt_tz = datetime(*dt_vals,tzinfo=tz)