Разбор строки даты / времени с сокращенным названием часового пояса в Python?

Я пытаюсь разобрать строки метки времени как "Sat, 11/01/09 8:00PM EST" в Python, но у меня возникают проблемы с поиском решения, которое будет обрабатывать сокращенный часовой пояс.

я использую dateutil "s parse() функция, но она не разбирает часовой пояс. Есть простой способ сделать это?

5 ответов

Решение

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

dateutil"s parser.parse() принимает в качестве аргумента ключевого слова tzinfos словарь такого рода {'EST': -5*3600} (то есть сопоставление имени зоны со смещением по Гринвичу в секундах). Итак, предполагая, что у нас это есть, мы можем сделать:

>>> import dateutil.parser as dp
>>> s = 'Sat, 11/01/09 8:00PM'
>>> for tz_code in ('PST','PDT','MST','MDT','CST','CDT','EST','EDT'):
>>>     dt = s+' '+tz_code
>>>     print dt, '=', dp.parse(dt, tzinfos=tzd)

Sat, 11/01/09 8:00PM PST = 2009-11-01 20:00:00-08:00
Sat, 11/01/09 8:00PM PDT = 2009-11-01 20:00:00-07:00
Sat, 11/01/09 8:00PM MST = 2009-11-01 20:00:00-07:00
Sat, 11/01/09 8:00PM MDT = 2009-11-01 20:00:00-06:00
Sat, 11/01/09 8:00PM CST = 2009-11-01 20:00:00-06:00
Sat, 11/01/09 8:00PM CDT = 2009-11-01 20:00:00-05:00
Sat, 11/01/09 8:00PM EST = 2009-11-01 20:00:00-05:00
Sat, 11/01/09 8:00PM EDT = 2009-11-01 20:00:00-04:00

Относительно содержания tzinfosвот как я заселил мой:

tz_str = '''-12 Y
-11 X NUT SST
-10 W CKT HAST HST TAHT TKT
-9 V AKST GAMT GIT HADT HNY
-8 U AKDT CIST HAY HNP PST PT
-7 T HAP HNR MST PDT
-6 S CST EAST GALT HAR HNC MDT
-5 R CDT COT EASST ECT EST ET HAC HNE PET
-4 Q AST BOT CLT COST EDT FKT GYT HAE HNA PYT
-3 P ADT ART BRT CLST FKST GFT HAA PMST PYST SRT UYT WGT
-2 O BRST FNT PMDT UYST WGST
-1 N AZOT CVT EGT
0 Z EGST GMT UTC WET WT
1 A CET DFT WAT WEDT WEST
2 B CAT CEDT CEST EET SAST WAST
3 C EAT EEDT EEST IDT MSK
4 D AMT AZT GET GST KUYT MSD MUT RET SAMT SCT
5 E AMST AQTT AZST HMT MAWT MVT PKT TFT TJT TMT UZT YEKT
6 F ALMT BIOT BTT IOT KGT NOVT OMST YEKST
7 G CXT DAVT HOVT ICT KRAT NOVST OMSST THA WIB
8 H ACT AWST BDT BNT CAST HKT IRKT KRAST MYT PHT SGT ULAT WITA WST
9 I AWDT IRKST JST KST PWT TLT WDT WIT YAKT
10 K AEST ChST PGT VLAT YAKST YAPT
11 L AEDT LHDT MAGT NCT PONT SBT VLAST VUT
12 M ANAST ANAT FJT GILT MAGST MHT NZST PETST PETT TVT WFT
13 FJST NZDT
11.5 NFT
10.5 ACDT LHST
9.5 ACST
6.5 CCT MMT
5.75 NPT
5.5 SLT
4.5 AFT IRDT
3.5 IRST
-2.5 HAT NDT
-3.5 HNT NST NT
-4.5 HLV VET
-9.5 MART MIT'''

tzd = {}
for tz_descr in map(str.split, tz_str.split('\n')):
    tz_offset = int(float(tz_descr[0]) * 3600)
    for tz_code in tz_descr[1:]:
        tzd[tz_code] = tz_offset

пс. в соответствии с @Hank Gay название часового пояса четко не определено. Для формирования моей таблицы я использовал http://www.timeanddate.com/library/abbreviations/timezones/ и http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations. Я смотрел на каждый конфликт и разрешал конфликты между непонятными и популярными именами по отношению к популярным (более используемым). Был один - IST - который не был таким четким (это может означать индийское стандартное время, иранское стандартное время, ирландское стандартное время или израильское стандартное время), поэтому я оставил его вне таблицы - возможно, вам придется выбрать, что добавить для этого на основе вашего местоположения. О - и я не учел Республику Кирибати с их абсурдным "посмотри на меня, я первый, чтобы праздновать Новый год" GMT+13 и GMT+14 часовых поясов.

Вы можете попробовать модуль pytz: http://pytz.sourceforge.net/

pytz переносит базу данных Olson tz в Python. Эта библиотека позволяет выполнять точные и кроссплатформенные расчеты часового пояса с использованием Python 2.3 или выше. Это также решает проблему неоднозначного времени в конце летнего времени, о чем вы можете прочитать в Справочнике по библиотеке Python (datetime.tzinfo).

Почти все часовые пояса Олсона поддерживаются.

Функция parse() в dateutil не может обрабатывать часовые пояса. То, что я использовал, это средство форматирования%Z и функция time.strptime(). Я понятия не имею, как она справляется с неоднозначностью в часовых поясах, но она, кажется, говорит о разнице между CDT и CST, и это все, что мне было нужно.

Предыстория: я храню резервные образы в каталогах, имена которых являются временными метками с использованием местного времени, так как у меня дома нет часов GMT. Поэтому я использую time.strptime(d, r"%Y-%m-%dT%H:%M:%S_%Z"), чтобы проанализировать имена каталогов обратно в фактическое время для анализа возраста.

Я понял, что dateparserможет решить эту проблему. https://pypi.org/project/dateparser/

Применение:

import dateparser


def time_gmt_format(str_datetime):
    # from string like "29/05/2020, 08:18 WIB" to GMT yyyymmddhhmmss

    date_time_obj = dateparser.parse(str_datetime, date_formats=['%d/%m/%Y, %H:%M %Z'], 
    settings={'TO_TIMEZONE': 'GMT'})  # convert to GMT datetime object

    return date_time_obj.strftime('%Y%m%d%H%M%S')  # Output: 20200529011800

Другие часовые пояса, поддерживаемые этой библиотекой: https://github.com/scrapinghub/dateparser/blob/e11a18a4d183a14211b28f5927ce01b220335881/dateparser/timezones.py

Я использовал pytz генерировать TZINFOS отображение:

from datetime import datetime as dt

import pytz

from dateutil.tz import gettz
from pytz import utc
from dateutil import parser


def gen_tzinfos():
    for zone in pytz.common_timezones:
        try:
            tzdate = pytz.timezone(zone).localize(dt.utcnow(), is_dst=None)
        except pytz.NonExistentTimeError:
            pass
        else:
            tzinfo = gettz(zone)

            if tzinfo:
                yield tzdate.tzname(), tzinfo

TZINFOS использование

>>> TZINFOS = dict(gen_tzinfos())
>>> TZINFOS
{'+02': tzfile('/usr/share/zoneinfo/Antarctica/Troll'),
 '+03': tzfile('/usr/share/zoneinfo/Europe/Volgograd'),
 '+04': tzfile('Europe/Ulyanovsk'),
 '+05': tzfile('/usr/share/zoneinfo/Indian/Kerguelen'),              
...
 'WGST': tzfile('/usr/share/zoneinfo/America/Godthab'),
 'WIB': tzfile('/usr/share/zoneinfo/Asia/Pontianak'),
 'WIT': tzfile('/usr/share/zoneinfo/Asia/Jayapura'),
 'WITA': tzfile('/usr/share/zoneinfo/Asia/Makassar'),
 'WSDT': tzfile('/usr/share/zoneinfo/Pacific/Apia'),
 'XJT': tzfile('/usr/share/zoneinfo/Asia/Urumqi')}

parser использование

>>> date_str = 'Sat, 11/01/09 8:00PM EST'
>>> tzdate = parser.parse(date_str, tzinfos=TZINFOS)
>>> tzdate.astimezone(utc)
datetime.datetime(2009, 11, 2, 1, 0, tzinfo=<UTC>)

Преобразование в UTC необходимо, поскольку для каждой аббревиатуры доступно много часовых поясов. поскольку TZINFOS это dict, он имеет только последний часовой пояс в аббревиатуре. И вы можете не получить тот, который вы ожидали до преобразования.

>>> tzdate
datetime.datetime(2009, 11, 1, 20, 0, tzinfo=tzfile('/usr/share/zoneinfo/America/Port-au-Prince'))
Другие вопросы по тегам