Error: time data does not match format ‘%Y-%m-%d %H:%M:%S.%f’

publicado por: Anonymous

Estoy intentando analizar los dias entre fechas que tengo en un archivo excel.
Cargo el archivo con pandas y defino la función

import datetime

def days_between(d1, d2):
    return abs(d2 - d1).days

Luego el codigo es el siguiente

grouped = df_.groupby('id')
c = 12
for x in grouped:
    print(type(x[1]['DATE'].values[0]))
    d1_str = str(x[1]['DATE'].values[0])
    d2_str = str(x[1]['DATE'].values[len(x[1]['DATE'])-1])
    d1 = datetime.datetime.strptime(d1_str, '%Y-%m-%d %H:%M:%S.%f')
    d2 = datetime.datetime.strptime(d2_str, '%Y-%m-%d %H:%M:%S.%f')
    d = days_between(d2, d1)

luego me tira el error

ValueError: time data '2019-03-22T11:09:27.000000000' does not match format '%Y-%m-%d %H:%M:%S.%f'

En el error veo que me lee uno de los datos como 2019-03-22T11:09:27.0000 con una “T” entremedio, no se a que se debe.

Los datos son del tipo

Los datos son del tipo

solución

Creo que estás buscando una solución para un problema que te has creado innecesariamente. Tu columna DATE es de tipo pandas.datetime64, no hay absolutamente ninguna necesidad de pasarla a datetime.datetime de Python estándar para operar. Con ello te complicas la vida y está haciendo una operación muy ineficiente dado que primero obtienes la representación en forma de cadena de la fecha, luego construyes el objeto datetime.datetime y terminas llamando a una función.

Para poder hacer reproducible el ejemplo, voy a partir de un xlsx con la siguiente estructura:

id    DATE
1     13/10/2019 12:24:27
2     14/10/2019 15:30:12
2     15/10/2019 14:24:17
1     16/10/2019 01:40:14
3     17/10/2019 12:03:27
4     18/10/2019 03:18:37
1     19/10/2019 12:04:55
2     20/10/2019 17:54:07
3     21/10/2019 14:14:17
4     22/10/2019 06:20:08
3     23/10/2019 02:57:03
3     24/10/2019 22:23:14
2     25/10/2019 19:47:27
4     26/10/2019 09:13:35

Primero de todo, para convertir de numpy.datetime64 a datetime.datetime no tienes que convertir a cadena y usar strptime, es mucho más simple y eficiente usar el método astype:

>>> import datetime
>>> import numpy as np

>>> np_dt64 = np.datetime64(datetime.datetime.now())
>>> np_dt64 
numpy.datetime64('2019-08-22T05:19:51.408199')
>>> str(np_dt64)
'2019-08-22T05:19:51.408199'
>>> dt = np_dt64.astype(datetime.datetime)
>>> dt
datetime.datetime(2019, 8, 22, 5, 19, 51, 408199)

por lo tanto, basta con que hacer en tu caso:

d1 = x[1]['DATE'].values[0]).astype(datetime.datetime)
d2 = x[1]['DATE'].values[-1]).astype(datetime.datetime)

Nota: recuerda que Python/NumPy permiten usar índices negativos, si quieres el último elemento de un array basta con hacer array[-1], no necesitas hacer array[len(array)-1]

Por otro lado, la conversión a datetime.datetime es innecesaria, siguiendo tu idea, puedes obtener la diferencia de días entre la primera y la última fila de cada grupo usando NumPy directamente:

import pandas as pd

df_ = pd.read_excel("test.xlsx")
grouped = df_.groupby('id')
for x in grouped:
    d1, d2 = x[1]['DATE'].values[[0, -1]]
    delta = d2 - d1
    dias = delta.astype('timedelta64[D]').item().days
    print(f"ID: {x[0]} DELTA: {dias} dias")
ID: 1 DELTA: 5 dias
ID: 2 DELTA: 11 dias
ID: 3 DELTA: 7 dias
ID: 4 DELTA: 8 dias

No obstante, por lo general cuando usas Pandas debes aprovecha siempre lo que éste y NumPy te ofrecen, evitando recurrir a ciclos y funciones Python crudas si no son estrictamente necesarias. Puedes hacer esto sin uso de ciclos directamente con Pandas, por ejemplo se me ocurre:

import pandas as pd
import datetime


df_ = pd.read_excel("test.xlsx")
deltas = (df_.groupby('id')
             .nth([0, -1])
             .groupby("id")
             .agg("diff")["DATE"]
             .dt
             .days)
deltas = deltas.loc[~deltas.index.duplicated(keep='last')]
id
1     5
2    11
3     7
4     8

El resultado es una Serie con la id como índice y su diferencia de días para su primera y última fecha como valor. Si alguna id tiene una sola fecha (una sola fila con esa id) aparece con el valor NaN.

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *