Как потребовать, чтобы временная метка была заполнена нулями во время проверки в Python?

Я пытаюсь проверить строку, которая должна содержать временную метку в формате ISO 8601 (обычно используется в JSON).

Python strptime кажется очень прощающим, когда дело доходит до проверки нулевого заполнения, см. пример кода ниже (обратите внимание, что в часе отсутствует нулевой уровень):

>>> import datetime
>>> s = '1985-08-23T3:00:00.000'
>>> datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f')
datetime.datetime(1985, 8, 23, 3, 0)

Он грациозно принимает строку, которая, например, не заполняется нулями в течение часа, и не генерирует исключение ValueError, как я ожидал.

Есть ли способ принудительно использовать strptime для проверки того, что он заполнен нулями? Или есть ли какая-либо другая встроенная функция в стандартных libs Python, которая делает?

Я бы не хотел писать свой собственный regexp для этого.

Ответ 1

Уже есть ответ, что синтаксический анализ ISO8601 или RFC3339 даты/времени с помощью Python strptime() невозможен: Как разобрать дату в формате ISO 8601? Итак, чтобы ответить на ваш вопрос, нет никакой возможности в стандартной библиотеке Python для надежного анализа такой даты. Что касается предложений регулярного выражения, строка даты, например

2020-14-32T45:33:44.123

приведет к допустимой дате. Существует много модулей Python (если вы ищете "iso8601" на https://pypi.python.org), но для создания полного ISO8601 Validator потребуются такие вещи, как прыжок секунд, список возможных значений смещения часового пояса и многое другое.

Ответ 2

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

import re

date_pattern = re.compile(r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}')
s_list = [
    '1985-08-23T3:00:00.000',
    '1985-08-23T03:00:00.000'
]
for s in s_list:
    if date_pattern.match(s):
        print "%s is valid" % s
    else:
        print "%s is invalid" % s

Выход

1985-08-23T3:00:00.000 is invalid
1985-08-23T03:00:00.000 is valid

Попробуйте на repl.it

Ответ 3

Чтобы принудительно выполнить strptime для проверки ведущих нулей для вас, вам придется добавить свои собственные литералы в Python _strptime._TimeRE_cache. Решение очень хакерское, скорее всего, не очень портативное и требует записи RegEx - хотя и только для часовой части отметки времени.

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

Ответ 4

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

Итак, если я правильно ее заработал, формат '%Y-%m-%dT%H:%M:%S.%f' и должен быть нулевым. Затем вы знаете точную длину строки, которую вы ищете, и воспроизведите предполагаемый результат.

import datetime
s = '1985-08-23T3:00:00.000'

stripped = datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f') 
try:
    assert len(s) == 23
except AssertionError:
    raise ValueError("time data '{}' does not match format '%Y-%m-%dT%H:%M:%S.%f".format(s))
else:
    print(stripped) #just for good measure

>>ValueError: time data '1985-08-23T3:00:00.000' does not match format '%Y-%m-%dT%H:%M:%S.%f