Jak parsować łańcuch czasu zawierający milisekundy w Pythonie?

204

Jestem w stanie analizować ciągi zawierające datę / godzinę z czasem. Strptime

>>> import time
>>> time.strptime('30/03/09 16:31:32', '%d/%m/%y %H:%M:%S')
(2009, 3, 30, 16, 31, 32, 0, 89, -1)

Jak parsować ciąg czasu zawierający milisekundy?

>>> time.strptime('30/03/09 16:31:32.123', '%d/%m/%y %H:%M:%S')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.5/_strptime.py", line 333, in strptime
    data_string[found.end():])
ValueError: unconverted data remains: .123
ilkinulas
źródło

Odpowiedzi:

317

Python 2.6 dodał nowe makro strftime / strptime %f, które wykonuje mikrosekundy. Nie jestem pewien, czy jest to gdzieś udokumentowane. Ale jeśli używasz wersji 2.6 lub 3.0, możesz to zrobić:

time.strptime('30/03/09 16:31:32.123', '%d/%m/%y %H:%M:%S.%f')

Edycja: Nigdy tak naprawdę nie pracuję z timemodułem, więc na początku tego nie zauważyłem, ale wygląda na to, że time.struct_time tak naprawdę nie przechowuje milisekund / mikrosekund. Lepiej skorzystaj z datetime:

>>> from datetime import datetime
>>> a = datetime.strptime('30/03/09 16:31:32.123', '%d/%m/%y %H:%M:%S.%f')
>>> a.microsecond
123000
DNS
źródło
4
Dzięki docs.python.org/library/datetime.html : Nowość w wersji 2.6: obiekty time i datetime obsługują kod w formacie% f, który rozszerza się do liczby mikrosekund w obiekcie, zerowany od lewej do sześciu miejsc.
ilkinulas
5
Woa, mogę powiedzieć, że dokumenty Python wymagają aktualizacji. Dokumenty modułu czasu nic nie mówią %f.
phunehehe
14
Dokumenty Pythona od wersji 2.7.3 są nieco mylące. W przypadku czasu% f może w rzeczywistości reprezentować dowolną liczbę miejsc po przecinku, a nie tylko 6, jak można oczekiwać w mikrosekundach. Tak więc powyższy kod przeanalizuje 32,122 sekundy i zapisze go jako 123 000µs, a tego właśnie chcemy.
Michael Scheper,
9
Liczba w %fjest uzupełniona zerami po prawej stronie (nie w lewo!) Do 6 miejsc po przecinku. 1 zostaje sparsowany do 100000, 12 zostaje sparsowany do 120000, a 1234567 produkujeValueError: unconverted data remains: 7
użytkownik443854
17
Czy to tylko ja, czy pytanie dotyczy milisekund, a nie mikrosekund?
Purrell,
12

Wiem, że to starsze pytanie, ale nadal używam Python 2.4.3 i musiałem znaleźć lepszy sposób na konwersję ciągu danych na datę i godzinę.

Rozwiązaniem, jeśli datetime nie obsługuje% f i nie wymaga próby / wyjątku, jest:

    (dt, mSecs) = row[5].strip().split(".") 
    dt = datetime.datetime(*time.strptime(dt, "%Y-%m-%d %H:%M:%S")[0:6])
    mSeconds = datetime.timedelta(microseconds = int(mSecs))
    fullDateTime = dt + mSeconds 

Działa to w przypadku ciągu wejściowego „2010-10-06 09: 42: 52.266000”

Andrew Stern
źródło
1
dt.replace(microsecond=int(mSecs))
haridsv
Dotyczy to Python 2.5 i wcześniejszych. Python 2.6 obsługuje strptime '% f'
smci
4

Aby podać kod, do którego odnosi się odpowiedź nstehr (z jego źródła ):

def timeparse(t, format):
    """Parse a time string that might contain fractions of a second.

    Fractional seconds are supported using a fragile, miserable hack.
    Given a time string like '02:03:04.234234' and a format string of
    '%H:%M:%S', time.strptime() will raise a ValueError with this
    message: 'unconverted data remains: .234234'.  If %S is in the
    format string and the ValueError matches as above, a datetime
    object will be created from the part that matches and the
    microseconds in the time string.
    """
    try:
        return datetime.datetime(*time.strptime(t, format)[0:6]).time()
    except ValueError, msg:
        if "%S" in format:
            msg = str(msg)
            mat = re.match(r"unconverted data remains:"
                           " \.([0-9]{1,6})$", msg)
            if mat is not None:
                # fractional seconds are present - this is the style
                # used by datetime's isoformat() method
                frac = "." + mat.group(1)
                t = t[:-len(frac)]
                t = datetime.datetime(*time.strptime(t, format)[0:6])
                microsecond = int(float(frac)*1e6)
                return t.replace(microsecond=microsecond)
            else:
                mat = re.match(r"unconverted data remains:"
                               " \,([0-9]{3,3})$", msg)
                if mat is not None:
                    # fractional seconds are present - this is the style
                    # used by the logging module
                    frac = "." + mat.group(1)
                    t = t[:-len(frac)]
                    t = datetime.datetime(*time.strptime(t, format)[0:6])
                    microsecond = int(float(frac)*1e6)
                    return t.replace(microsecond=microsecond)

        raise
Phil H.
źródło
2

Powyższa odpowiedź DNS jest w rzeczywistości niepoprawna. SO pyta o milisekundy, ale odpowiedź dotyczy mikrosekund. Niestety, Python nie ma dyrektywy dla milisekund, tylko mikrosekundy (patrz dokument ), ale można to obejść, dodając trzy zera na końcu ciągu i analizując ciąg jako mikrosekundy, coś w stylu:

datetime.strptime(time_str + '000', '%d/%m/%y %H:%M:%S.%f')

gdzie time_strjest sformatowany jak 30/03/09 16:31:32.123.

Mam nadzieję że to pomoże.

Rafid
źródło
2
Początkowo myślałem o tym samym, ale zobacz komentarze na temat odpowiedzi i dokumentów . Ma mikrosekundy od lewej do zera , więc .123jest poprawnie interpretowany jako 123 000 mikrosekund
aschmied
1

Moją pierwszą myślą było spróbowanie podania go „30/03/09 16: 31: 32.123” (z kropką zamiast dwukropka między sekundami a milisekundami). Ale to nie zadziałało. Szybkie spojrzenie na dokumentację wskazuje, że ułamki sekund są w każdym razie ignorowane ...

Ach, różnice wersji. Zostało to zgłoszone jako błąd i teraz w 2.6+ można użyć „% S.% f”, aby je przeanalizować.

MarkusQ
źródło
To nie działa; time.strptime po prostu nie robi milisekund.
DNS
1

z list mailowych Pythona: parsowanie wątku milisekundowego . Jest tam opublikowana funkcja, która zdaje się wykonywać zadanie, chociaż jak wspomniano w komentarzach autora, jest to rodzaj włamania. Używa wyrażeń regularnych do obsługi zgłaszanego wyjątku, a następnie wykonuje pewne obliczenia.

Możesz także spróbować wykonać wyrażenia regularne i obliczenia z góry, zanim przekażesz je do strptime.

nstehr
źródło
tak, znam ten wątek. Ale szukam prostszego sposobu. czy w standardowej wersji biblioteki python jest moduł, który analizuje czas z milisekundami?
ilkinulas
1

Zrobiłem to dla Pythona 2

print ( time.strftime("%H:%M:%S", time.localtime(time.time())) + "." + str(time.time()).split(".",1)[1])

wypisuje czas „% H:% M:% S”, dzieli time.time () na dwa podłańcuchy (przed i po.) xxxxxxx.xx, a ponieważ .xx to moje milisekundy, dodaję drugi podłańcuch do mojego „% H:% M:% S ”

mam nadzieję, że to ma sens :) Przykładowy wynik:

13: 31: 21.72 Mrugnięcie 01


13: 31: 21,81 KONIEC RÓŻNICY 01


13: 31: 26,3 Mrugnięcie 01


13: 31: 26,39 KONIEC RÓŻNICY 01


13: 31: 34.65 Linia startowa 01


Papatrexas
źródło