2017-08-09 8 views
11

Próbuję sprawdzić ciąg znaków, który powinien zawierać znacznik czasu w formacie ISO 8601 (zwykle używany w JSON).Jak wymagać, aby znacznik czasu był wyzerowany podczas sprawdzania poprawności w języku Python?

Pythona strptime wydaje się być bardzo wyrozumiały, jeśli chodzi o sprawdzanie zerami, patrz przykład kodu poniżej (należy pamiętać, że godziny brakuje zero):

>>> 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) 

ona wdzięcznie przyjmuje ciąg znaków, który nie jest wyzerowane na godzinę, na przykład, i nie wyrzuca wyjątku, tak jak się spodziewałem.

Czy istnieje sposób na wymuszenie działania w celu sprawdzenia, czy jest on zerowy? Czy jest tam jakaś inna wbudowana funkcja w standardowych bibliotekach Pythona, która to robi?

Chciałbym uniknąć napisania do tego własnego regexp.

+1

Możesz tylko sprawdzić poprawność łańcucha ręcznie: sprawdź, czy '.' jest we właściwej pozycji (' str [19] == '.''): jeśli tak nie jest, to jest problem z zerowym dopełnieniem. – TemporalWolf

+0

Być może nie to konkretne pytanie, ale inne kwestie związane z ISO8601 zostały omówione na SO. Jedno pytanie wymienia https://pypi.python.org/pypi/iso8601, które z kolei wspomina http://labix.org/python-dateutil. –

Odpowiedz

4

Jest już odpowiedź, że parsowania ISO8601 lub RFC3339 datę/czas z Python strptime() jest niemożliwy: How to parse an ISO 8601-formatted date? Tak więc, aby odpowiedzieć na twoje pytanie, nie ma żadnej możliwości w standardowej bibliotece Pythona na niezawodne przetwarzanie, takie jak randka. chodzi regex sugestie, datę ciąg jak

2020-14-32T45:33:44.123 

skutkowałoby ważnej dacie.Istnieje wiele modułów Pythona (jeśli wyszukujesz "iso8601" na https://pypi.python.org), ale zbudowanie kompletnego Validatora ISO8601 wymagałoby takich rzeczy jak sekundy przestępne, lista możliwych wartości przesunięcia strefy czasowej i wiele innych.

0

Aby wymusić wprowadzenie strptime w celu potwierdzenia zer wiodących dla Ciebie, musisz dodać własne literały do ​​Pythona _strptime._TimeRE_cache. Rozwiązanie jest bardzo hackowate, najprawdopodobniej niezbyt przenośne i wymaga napisania RegEx - choć tylko na godzinę w sygnaturze czasowej.

Innym rozwiązaniem tego problemu byłoby napisanie własnej funkcji, która używa strptime, a także konwertuje przeanalizowaną datę z powrotem na ciąg i porównuje dwa ciągi. To rozwiązanie jest przenośne, ale brakuje mu jasnych komunikatów o błędach - nie będziesz w stanie rozróżnić brakujących początkowych zer w godzinach, minutach, sekundach.

0

Jedyna rzecz, jaką mogę wymyślić poza obcięciem z wewnętrznymi wersjami Pythona, to przetestować poprawność formatu, wiedząc, czego szukasz.

Tak więc, jeśli zbieram to dobrze, formatem jest '%Y-%m-%dT%H:%M:%S.%f' i powinien on wynosić zero. Następnie należy znać dokładną długość ciągu którego szukasz i odtworzenia zamierzonego rezultatu ..

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 
+0

Dzięki takiemu podejściu musisz uważać na 'strip()' twoje wejście, lub ciągnący znak nowej linii może dać ci fałszywą, dobrą wartość. – TemporalWolf

+0

Wtedy natkniesz się na "ValueError: nieprzekształcone dane pozostają:" według wartości strptime. Czy brakuje mi tutaj czegoś? – Uvar

1

Mówiłeś chcesz uniknąć regex, ale w rzeczywistości jest to rodzaj problemu, gdy jest regex właściwy. Jak odkryłeś, strptime jest bardzo elastyczny pod względem danych wejściowych, które zaakceptuje. Jednak regex dla tego problemu jest stosunkowo łatwy do komponowania:

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 

wyjście

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

Wypróbuj repl.it

Powiązane problemy