¿Cómo puedo analizar una cadena de tiempo que contiene milisegundos con Python?


204

Puedo analizar cadenas que contienen fecha / hora con time.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)

¿Cómo puedo analizar una cadena de tiempo que contiene milisegundos?

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

Respuestas:


318

Python 2.6 agregó una nueva macro strftime / strptime %f, que hace microsegundos. No estoy seguro si esto está documentado en alguna parte. Pero si está utilizando 2.6 o 3.0, puede hacer esto:

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

Editar: Realmente nunca trabajo con el timemódulo, por lo que no me di cuenta al principio, pero parece que time.struct_time en realidad no almacena milisegundos / microsegundos. Puede que sea mejor usarlo datetimeasí:

>>> from datetime import datetime
>>> a = datetime.strptime('30/03/09 16:31:32.123', '%d/%m/%y %H:%M:%S.%f')
>>> a.microsecond
123000

44
Gracias docs.python.org/library/datetime.html : Nuevo en la versión 2.6: los objetos de hora y fecha y hora admiten un código de formato% f que se expande a la cantidad de microsegundos en el objeto, con relleno de cero a la izquierda a seis lugares.
ilkinulas

55
Woa, puedo decir que los documentos de Python necesitan actualización. Docs para el módulo de tiempo no dice nada al respecto %f.
phunehehe

14
Los documentos de Python, a partir de la versión 2.7.3, son un poco engañosos. Para strptime,% f en realidad puede representar cualquier número de decimales, no solo 6, como cabría esperar para microsegundos. Entonces, el código anterior analizaría 32.123 segundos y lo almacenaría como 123,000µs, que es lo que queremos.
Michael Scheper el

9
El número %fse rellena con ceros a la derecha (¡no a la izquierda!) Con 6 decimales. 1 se analiza a 100000, 12 se analiza a 120000 y 1234567 produceValueError: unconverted data remains: 7
user443854

17
¿Soy solo yo o era la pregunta sobre milisegundos, no microsegundos?
Purrell

12

Sé que esta es una pregunta anterior, pero todavía estoy usando Python 2.4.3 y necesitaba encontrar una mejor manera de convertir la cadena de datos a una fecha y hora.

La solución si datetime no admite% f y sin necesidad de probar / excepto es:

    (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 

Esto funciona para la cadena de entrada "2010-10-06 09: 42: 52.266000"


1
dt.replace(microsecond=int(mSecs))
haridsv

Esto se aplica a Python 2.5 y versiones anteriores. Python 2.6 admite strptime '% f'
smci

4

Para dar el código al que se refiere la respuesta de nstehr (desde su fuente ):

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

2

La respuesta DNS anterior es realmente incorrecta. El SO pregunta por milisegundos, pero la respuesta es por microsegundos. Desafortunadamente, Python`s no tiene una directiva para milisegundos, solo microsegundos (ver documento ), pero puede solucionarlo agregando tres ceros al final de la cadena y analizando la cadena como microsegundos, algo así como:

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

donde time_strestá formateado como 30/03/09 16:31:32.123.

Espero que esto ayude.


2
Al principio pensé lo mismo, pero veo los comentarios sobre la respuesta y los documentos . Es microsegundos .123
rellenos

1

Mi primer pensamiento fue intentar pasarlo '30 / 03/09 16: 31: 32.123 '(con un punto en lugar de dos puntos entre los segundos y los milisegundos). Pero eso no funcionó. Un rápido vistazo a los documentos indica que los segundos fraccionarios se ignoran en cualquier caso ...

Ah, diferencias de versión. Esto se informó como un error y ahora en 2.6+ puede usar "% S.% f" para analizarlo.


Eso no funciona time.strptime simplemente no hace milisegundos.
DNS

1

de las listas de correo de Python: análisis de hilos de milisegundos . Hay una función publicada allí que parece hacer el trabajo, aunque como se menciona en los comentarios del autor, es una especie de truco. Utiliza expresiones regulares para manejar la excepción que se genera, y luego hace algunos cálculos.

También puede intentar hacer las expresiones regulares y los cálculos por adelantado, antes de pasarlo a strptime.


Sí, conozco ese hilo. Pero estoy buscando una manera más simple. ¿hay algún módulo en la biblioteca estándar de python que haga que el tiempo se analice con milisegundos?
ilkinulas

1

Para Python 2 hice esto

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

imprime el tiempo "% H:% M:% S", divide el time.time () en dos subcadenas (antes y después de.) xxxxxxx.xx y como .xx son mis milisegundos, agrego la segunda subcadena a mi "% H:% M:% S "

espero que tenga sentido :) Ejemplo de salida:

13: 31: 21.72 Parpadeo 01


13: 31: 21.81 FIN DE BLINK 01


13: 31: 26.3 Parpadeo 01


13: 31: 26.39 FIN DE BLINK 01


13: 31: 34.65 Carril inicial 01


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.