2016-12-13 3 views
1

Ich möchte eine Funktion schreiben, die eine Zeichenfolge und True zurückgibt, wenn es eine gültige ISO-8601 Datetime ist - präzise in Mikrosekunden, einschließlich einer Zeitzone Offset - False andernfalls.Validieren Sie eine ISO-8601-Datetime-Zeichenfolge in Python?

Ich habe otherquestions gefunden, dass verschiedene Arten von Parsen Datetime Strings liefern, aber ich mag nur True im Fall von ISO-8601-Format zurückzukehren. Das Parsen hilft mir nicht, wenn ich nicht einen Fehler für Formate erzeugen kann, die nicht ISO-8601 entsprechen.

(Ich benutze die schöne arrow Bibliothek an anderer Stelle in meinem Code eine Lösung, die arrow verwendet wäre willkommen..)


EDIT: Es scheint, dass eine allgemeine Lösung für „diese Zeichenfolge a gültiges ISO 8601 datetime "existiert nicht unter den üblichen Python-Datetime-Paketen.

Also, diese Frage schmaler zu machen, konkreter und verantwortlich, ich für ein Format-String absetzen, die eine Datetime-Zeichenfolge in dieser Form validieren:

'2016-12-13T21:20:37.593194+00:00' 

Derzeit bin ich mit:

format_string = '%Y-%m-%dT%H:%M:%S.%f%z' 
datetime.datetime.strptime(my_timestamp, format_string) 

Dies gibt:

ValueError: time data '2016-12-13T21:20:37.593194+00:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z' 

Das Problem mit dem Doppelpunkt in der UTC zu liegen scheint fset (+00:00). Wenn ich einen Offset ohne einen Doppelpunkt verwende (z. B. '2016-12-13T21:20:37.593194+0000'), wird dieser korrekt wie erwartet analysiert. Dies ist offensichtlich, weil 's %z Token does not respect the UTC offset form that has a colon, nur die Form ohne, obwohl both are valid per the spec.

+0

Das Format ist streng genug, dass es wäre nicht schwer, es einfach auf die harte Art und Weise zu validieren. –

+0

Und Sie haben versucht ... was genau? – jonrsharpe

+1

Haben Sie sich das Paket 'iso8601' auf PyPI angesehen? –

Antwort

1

Angesichts der Einschränkungen, die Sie auf das Problem haben, könnten Sie es leicht mit einem regulären Ausdruck lösen.

>>> import re 
>>> re.match(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{6}[+-]\d\d:\d\d$', '2016-12-13T21:20:37.593194+00:00') 
<_sre.SRE_Match object; span=(0, 32), match='2016-12-13T21:20:37.593194+00:00'> 

Wenn Sie alle Variationen von ISO 8601 übergeben müssen wird es ein viel komplizierterer regulärer Ausdruck, aber es immer noch getan werden könnte. Wenn Sie auch die numerischen Bereiche validieren müssen, z. B. überprüfen, ob die Stunde zwischen 0 und 23 liegt, können Sie Klammern in den regulären Ausdruck einfügen, um Übereinstimmungsgruppen zu erstellen, und anschließend jede Gruppe überprüfen. Hier

+0

Vielen Dank für den Vorschlag! Ich wollte vermeiden, meine eigene Date-Parsing-Implementierung zu rollen, weil andere dies bereits getan haben. Ich bevorzuge es, das Rad nicht neu zu erfinden, und ich verwende lieber Code, der von vielen anderen benutzt und getestet wurde, wann immer es möglich ist. – Stew

0

ist eine grobe, aber funktionelle Lösung (für die engere Frage) unter Verwendung von datetime.strptime():

import datetime 

def is_expected_datetime_format(timestamp): 
    format_string = '%Y-%m-%dT%H:%M:%S.%f%z' 
    try: 
     colon = timestamp[-3] 
     if not colon == ':': 
      raise ValueError() 
     colonless_timestamp = timestamp[:-3] + timestamp[-2:] 
     datetime.datetime.strptime(colonless_timestamp, format_string) 
     return True 
    except ValueError: 
     return False 
0

https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html

gibt viele Varianten für die Validierung von Datum und Zeit in ISO8601-Format (zB 2008-08- 30T01: 45: 36 oder 2008-08-30T01: 45: 36.123Z).Die Regex für den XML-Schema-Datums- und Uhrzeittyp wird als gegeben:

>>> regex = r'^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$' 

Also, um Sie tun könnten, zu überprüfen:

>>> import re 
>>> match_iso8601 = re.compile(regex).match 
>>> def validate_iso8601(str_val): 
...  try:    
...   if match_iso8601(str_val) is not None: 
...    return True 
...  except: 
...   pass 
...  return False 

Einige Beispiele:

>>> validate_iso8601('2017-01-01') 
False 

>>> validate_iso8601('2008-08-30T01:45:36.123Z') 
True 

>>> validate_iso8601('2016-12-13T21:20:37.593194+00:00') 
True