Strptime () та часові пояси Python?


157

У мене є CSV dumpfile із резервної копії IPD Blackberry, створений за допомогою IPDDump. Рядки дати / часу тут виглядають приблизно так (де ESTє часовий пояс в Австралії):

Tue Jun 22 07:46:22 EST 2010

Мені потрібно мати змогу проаналізувати цю дату в Python. Спочатку я спробував використовувати strptime()функцію з дати.

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

Однак чомусь datetimeоб’єкт, який повертається, схоже, не tzinfoпов'язаний з ним.

Я читав на цій сторінці, що, мабуть, datetime.strptimeмовчки відкидає tzinfo, проте перевірив документацію, і нічого не можу знайти тут .

Мені вдалося розібрати дату за допомогою сторонньої бібліотеки Python, dateutil , однак мені все ще цікаво, як я strptime()неправильно використовував вбудовану ? Чи є якийсь спосіб змусити strptime()гарно грати з часовими поясами?


1
Ви не можете просто перетворити всі дати в GMT?
Робус

2
@Robus: Хм, я сподівався зробити це - але я припускав, що строфіл / дата може якось це зробити? Так чи інакше, мені потрібно зберігати / аналізувати той факт, що дати перебувають у часовому поясі EST, або в будь-якому часовому поясі вони трапляються зі мною. Сценарій повинен мати можливість аналізувати загальні дати з інформацією про часовий пояс (наприклад, ETC може бути будь-яким іншим часовим поясом).
victorhooi

3
EST - це також абревіатура часового поясу в США. (Аналогічно BST є і Великобританією, і бразильським скороченням часового поясу.) Такі абревіатури за своєю суттю неоднозначні. Використовуйте заміщення відносно UTC / GMT. (Якщо вам потрібно підтримати абревіатури, вам потрібно зробити відображення залежним від локалі, і це брудна щуряча яма.)
Дональд стипендіатів

Відповіді:


58

Документація 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 (), буде створений відомий об'єкт дати. 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

13
Пов'язана помилка Python: % Z у strptime не відповідає EST та іншим
jfs

353

Я рекомендую використовувати 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, вибач за це. Але я сподіваюся, що ця відповідь все-таки корисна іншим людям, які натрапляють на це запитання, коли у них є питання розбору дати та бачать корисність цього модуля.


Зважаючи на те, що так багато людей схильні використовувати python-dateutil, я хотів би вказати нам на одне обмеження цієї ліб. >>> parser.parse("Thu, 25 Sep 2003 10:49:41,123 -0300") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Users/wanghq/awscli/lib/python2.7/site-packages/dateutil/parser.py", line 748, in parse return DEFAULTPARSER.parse(timestr, **kwargs) File "/Users/wanghq/awscli/lib/python2.7/site-packages/dateutil/parser.py", line 310, in parse res, skipped_tokens = self._parse(timestr, **kwargs) TypeError: 'NoneType' object is not iterable
wanghq

1
@wanghq вам потрібно замінити останню кому крапкою. Потімparser.parse("Thu, 25 Sep 2003 10:49:41.123 -0300") returns: datetime.datetime(2003, 9, 25, 10, 49, 41, 123000, tzinfo=tzoffset(None, -10800))
flyingfoxlee

7
@flyingfoxlee, так, я розумію це. Я просто хочу сказати людям обмеження python-dateutil. Він робить магічні речі, але іноді цього не робить. Тож "просто киньте побачення на це, і це робить правильну річ". не на 100% правда.
wanghq

4
dateutil.parser.parse("10-27-2016 09:06 AM PDT")повертається: datetime.datetime(2016, 10, 27, 9, 6)не вдалося визначити часовий пояс ...
HaPsantran

2
Це залежить від своєї мети. dateutil parserможе бути простим у використанні, але strptime()швидшим. Крім того, його формати досить легко засвоїти.
захоплення

9

Ваш часовий рядок схожий на формат часу в 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)

Дивіться рішення, які дають об'єкти дат часу, відомі часовому поясу для різних версій Python: аналіз дати з часовим поясом з електронної пошти .

У цьому форматі ESTсемантично еквівалентний-0500 . Хоча, як правило, абревіатури часового поясу недостатньо, щоб однозначно визначити часовий пояс .


0

Потрапив у цю точну проблему.

Що я закінчив робити:

# 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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.