Преобразование строк (имеющих разные форматы) в дату и время в Python

avatar
raghav
8 августа 2021 в 22:17
87
2
-2

У меня есть следующий кадр данных:

df= {'DateTime': {0: '2017-08-02T00:00:00Z', 1: '2017-08-02T00:00:00.050Z', 2: '2017-08 02T00:00:00.100Z', 3: '2017-08-02T00:00:00.150Z', 4: '2017-08-02T00:00:00.200Z', 5: '2017-08 02T00:00:00.250Z', 6: '2017-08-02T00:00:00.300Z', 7: '2017-08-02T00:00:00.350Z', 8: '2017-08 02T00:00:00.400Z', 9: '2017-08-02T00:00:00.450Z', 10: '2017-08-02T00:00:00.500Z', 11: '2017-08 02T00:00:00.550Z', 12: '2017-08-02T00:00:00.600Z', 13: '2017-08-02T00:00:00.650Z', 14: '2017-08 02T00:00:00.700Z', 15: '2017-08-02T00:00:00.750Z', 16: '2017-08-02T00:00:00.800Z', 17: '2017-08 02T00:00:00.850Z', 18: '2017-08-02T00:00:00.900Z', 19: '2017-08-02T00:00:00.950Z', 20: '2017-08-02T00:00:01Z'}}

Я хочу преобразовать столбец "DateTime" в формат datetime, но проблема в том, что строки имеют разные шаблоны. Например. первая строка имеет формат "%Y-%m-%dT%H:%M:%SZ", но строки 2-19 имеют формат "%Y-%m-%dT%H:%M:%S.%fZ", а 20-я строка снова имеет формат "%Y-%m-%dT%H:%M:%SZ". Как такой столбец можно преобразовать в datetime?

Источник
fsimonjetz
8 августа 2021 в 22:40
3

Вам действительно нужно указывать форматы? df.DateTime.apply(pd.to_datetime) без какого-либо набора форматов работает нормально...

raghav
8 августа 2021 в 22:50
0

Верный! Но вывод похож на 2017-08-02 00:00:00+00:00, 2017-08-02 00:00:00.050000+00:00, ...... Нет ли проблем с +00: 00?

fsimonjetz
8 августа 2021 в 23:09
0

У меня нет большого опыта работы с объектами даты и времени, но я не думаю, что это проблема, после преобразования в дату и время вы можете избавиться от часового пояса с помощью df.DateTime.dt.tz_localize(None).

FObersteiner
9 августа 2021 в 06:54
2

@fsimonjetz, вы должны были добавить это как ответ ;-) Принятый слишком усложняет ситуацию, имхо. +00:00 означает UTC, так как в вашем вводе есть Z (формат ISO 8601, кстати, Z для зулусского времени), так что это абсолютно правильно.

Ответы (2)

avatar
MDR
8 августа 2021 в 23:11
2

Возможно...

Просто:

    import pandas as pd
    
    df = pd.DataFrame({'DateTime': {0: '2017-08-02T00:00:00Z', 1: '2017-08-02T00:00:00.050Z', 2: '2017-08 02T00:00:00.100Z', 3: '2017-08-02T00:00:00.150Z', 4: '2017-08-02T00:00:00.200Z', 5: '2017-08 02T00:00:00.250Z', 6: '2017-08-02T00:00:00.300Z', 7: '2017-08-02T00:00:00.350Z', 8: '2017-08 02T00:00:00.400Z', 9: '2017-08-02T00:00:00.450Z', 10: '2017-08-02T00:00:00.500Z', 11: '2017-08 02T00:00:00.550Z', 12: '2017-08-02T00:00:00.600Z', 13: '2017-08-02T00:00:00.650Z', 14: '2017-08 02T00:00:00.700Z', 15: '2017-08-02T00:00:00.750Z', 16: '2017-08-02T00:00:00.800Z', 17: '2017-08 02T00:00:00.850Z', 18: '2017-08-02T00:00:00.900Z', 19: '2017-08-02T00:00:00.950Z', 20: '2017-08-02T00:00:01Z'}})
    
    df['DateTime'] = pd.to_datetime(df['DateTime']).dt.tz_localize(None)

Или:

    import pandas as pd
    from dateutil.parser import parse
    
    df = pd.DataFrame({'DateTime': {0: '2017-08-02T00:00:00Z', 1: '2017-08-02T00:00:00.050Z', 2: '2017-08 02T00:00:00.100Z', 3: '2017-08-02T00:00:00.150Z', 4: '2017-08-02T00:00:00.200Z', 5: '2017-08 02T00:00:00.250Z', 6: '2017-08-02T00:00:00.300Z', 7: '2017-08-02T00:00:00.350Z', 8: '2017-08 02T00:00:00.400Z', 9: '2017-08-02T00:00:00.450Z', 10: '2017-08-02T00:00:00.500Z', 11: '2017-08 02T00:00:00.550Z', 12: '2017-08-02T00:00:00.600Z', 13: '2017-08-02T00:00:00.650Z', 14: '2017-08 02T00:00:00.700Z', 15: '2017-08-02T00:00:00.750Z', 16: '2017-08-02T00:00:00.800Z', 17: '2017-08 02T00:00:00.850Z', 18: '2017-08-02T00:00:00.900Z', 19: '2017-08-02T00:00:00.950Z', 20: '2017-08-02T00:00:01Z'}})
    
    df['DateTime'] = df['DateTime'].apply(lambda x: parse(x))
    df['DateTime'] = df['DateTime'].apply(lambda x: x.strftime('%Y-%m-%d %H:%M:%S.%f'))

Или:

import pandas as pd
import dateparser

df['DateTime'] = df['DateTime'].apply(lambda x: dateparser.parse(x).strftime('%Y-%m-%d %H:%M:%S.%f'))

Вывод:

    DateTime
0   2017-08-02 00:00:00.000000
1   2017-08-02 00:00:00.050000
2   2017-08-02 00:00:00.100000
3   2017-08-02 00:00:00.150000
4   2017-08-02 00:00:00.200000
5   2017-08-02 00:00:00.250000
6   2017-08-02 00:00:00.300000
7   2017-08-02 00:00:00.350000
8   2017-08-02 00:00:00.400000
9   2017-08-02 00:00:00.450000
10  2017-08-02 00:00:00.500000
11  2017-08-02 00:00:00.550000
12  2017-08-02 00:00:00.600000
13  2017-08-02 00:00:00.650000
14  2017-08-02 00:00:00.700000
15  2017-08-02 00:00:00.750000
16  2017-08-02 00:00:00.800000
17  2017-08-02 00:00:00.850000
18  2017-08-02 00:00:00.900000
19  2017-08-02 00:00:00.950000
20  2017-08-02 00:00:01.000000
FObersteiner
9 августа 2021 в 06:52
1

Я думаю, что это слишком сложно. Простой df['DateTime'] = pd.to_datetime(df['DateTime']) делает свое дело. Если вы не хотите указывать часовой пояс, выполните локализацию на None (.dt.tz_localize(None)).

MDR
9 августа 2021 в 09:45
0

Нп. Добавлена ​​возможность сделать его доступным.

FObersteiner
9 августа 2021 в 10:45
0

спасибо за обновление, я бы поставил это как первый вариант ^^ кстати. Я не минусовал.

MDR
9 августа 2021 в 11:20
1

Готово. На данный момент голосование 50/50. Настоящий ответ Marmite.

avatar
Psidom
8 августа 2021 в 22:31
1

Один из вариантов — попытаться преобразовать каждый формат отдельно, а затем объединить результаты:

formats = ["%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m %dT%H:%M:%S.%fZ"]
parsed_dt = pd.to_datetime(df.DateTime, format=formats[0], errors='coerce')
for format in formats[1:]:
    parsed_dt = parsed_dt.fillna(pd.to_datetime(df.DateTime, format=format, errors='coerce'))

parsed_dt
0    2017-08-02 00:00:00.000
1    2017-08-02 00:00:00.050
2    2017-08-02 00:00:00.100
3    2017-08-02 00:00:00.150
4    2017-08-02 00:00:00.200
5    2017-08-02 00:00:00.250
6    2017-08-02 00:00:00.300
7    2017-08-02 00:00:00.350
8    2017-08-02 00:00:00.400
9    2017-08-02 00:00:00.450
10   2017-08-02 00:00:00.500
11   2017-08-02 00:00:00.550
12   2017-08-02 00:00:00.600
13   2017-08-02 00:00:00.650
14   2017-08-02 00:00:00.700
15   2017-08-02 00:00:00.750
16   2017-08-02 00:00:00.800
17   2017-08-02 00:00:00.850
18   2017-08-02 00:00:00.900
19   2017-08-02 00:00:00.950
20   2017-08-02 00:00:01.000
Name: DateTime, dtype: datetime64[ns]