Создание pandas DatetimeIndex в Dataframe из объектов datetime, поддерживающих DST

Из онлайн-API я собираю серию точек данных, каждая из которых имеет значение и временную метку ISO. К сожалению, мне нужно перебрать их, поэтому я сохраняю их во временном dict, а затем создаю из него фрейм данных pandas и устанавливаю индекс в столбец временной метки (упрощенный пример):

from datetime import datetime
import pandas


input_data = [
    '2019-09-16T06:44:01+02:00',
    '2019-11-11T09:13:01+01:00',
]

data = []
for timestamp in input_data:
    _date = datetime.fromisoformat(timestamp)

    data.append({'time': _date})

pd_data = pandas.DataFrame(data).set_index('time')

Пока все временные метки находятся в одном часовом поясе и DST / не-DST, все работает нормально, и я получаю Dataframe с DatetimeIndex, с которым я могу работать позже. Однако, как только в одном наборе данных появляются два разных смещения по времени (пример выше), я получаю только Index в моем фрейме данных, который не поддерживает какие-либо методы, основанные на времени.

Есть ли способ заставить панды принимать временные зоны с разной датой в качестве индекса?


person Timm    schedule 19.08.2020    source источник


Ответы (3)


  • Столбец pandas datetime также требует, чтобы смещение было таким же. Столбец с другим смещением не будет преобразован в datetime dtype.
  • Я предлагаю не преобразовывать данные в дату и время, пока они не появятся в пандах.
  • Разделите смещение по времени и рассматривайте его как timedelta
  • to_timedelta требует формата 'hh:mm:ss', поэтому добавьте ':00' в конец смещения
  • См. Панды: дельты времени для всех доступных операций timedelta.
  • pandas.Series.dt.tz_convert
  • pandas.Series.tz_localize
  • Convert to a specific TZ with:
    • If a datetime is not datetime64[ns, UTC] dtype, then first use .dt.tz_localize('UTC') before .dt.tz_convert('US/Pacific')
    • В противном случае df.datetime_utc.dt.tz_convert('US/Pacific')
import pandas as pd

# sample data
input_data = ['2019-09-16T06:44:01+02:00', '2019-11-11T09:13:01+01:00']

# dataframe
df = pd.DataFrame(input_data, columns=['datetime'])

# separate the offset from the datetime and convert it to a timedelta
df['offset'] = pd.to_timedelta(df.datetime.str[-6:] + ':00')

# if desired, create a str with the separated datetime
# converting this to a datetime will lead to AmbiguousTimeError because of overlapping datetimes at 2AM, per the OP
df['datetime_str'] = df.datetime.str[:-6]

# convert the datetime column to a datetime format without the offset
df['datetime_utc'] = pd.to_datetime(df.datetime, utc=True)

# display(df)
                    datetime          offset        datetime_str              datetime_utc
0  2019-09-16T06:44:01+02:00 0 days 02:00:00 2019-09-16 06:44:01 2019-09-16 04:44:01+00:00
1  2019-11-11T09:13:01+01:00 0 days 01:00:00 2019-11-11 09:13:01 2019-11-11 08:13:01+00:00

print(df.info())
[out]:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 4 columns):
 #   Column        Non-Null Count  Dtype              
---  ------        --------------  -----              
 0   datetime      2 non-null      object             
 1   offset        2 non-null      timedelta64[ns]    
 2   datetime_str  2 non-null      object             
 3   datetime_utc  2 non-null      datetime64[ns, UTC]
dtypes: datetime64[ns, UTC](1), object(2), timedelta64[ns](1)
memory usage: 192.0+ bytes

# convert to local timezone
df.datetime_utc.dt.tz_convert('US/Pacific')

[out]:
0   2019-09-15 21:44:01-07:00
1   2019-11-11 00:13:01-08:00
Name: datetime_utc, dtype: datetime64[ns, US/Pacific]

Другие источники

person Trenton McKinney    schedule 19.08.2020
comment
@Timm Я обновил ответ, чтобы отразить дополнительную информацию. - person Trenton McKinney; 21.08.2020

Небольшое исправление формулировки вопроса (что считаю важным). У вас есть смещение по всемирному координированному времени - для перехода на летнее время / без перехода на летнее время потребуется больше информации, то есть часовой пояс. Здесь это имеет значение, поскольку вы можете легко анализировать временные метки со смещениями UTC (даже разными) на UTC:

import pandas as pd

input_data = [
    '2019-09-16T06:44:01+02:00',
    '2019-11-11T09:13:01+01:00',
]

dti = pd.to_datetime(input_data, utc=True)
# dti
# DatetimeIndex(['2019-09-16 04:44:01+00:00', '2019-11-11 08:13:01+00:00'], dtype='datetime64[ns, UTC]', freq=None)

Я всегда предпочитаю работать с UTC, так что меня это устроит. Если, однако, вам действительно нужно datetime в определенном часовом поясе, вы можете преобразовать, например, в виде

dti = dti.tz_convert('Europe/Berlin')
# dti
# DatetimeIndex(['2019-09-16 06:44:01+02:00', '2019-11-11 09:13:01+01:00'], dtype='datetime64[ns, Europe/Berlin]', freq=None)
person MrFuppes    schedule 20.08.2020
comment
Ваше исправление абсолютно правильное и важное. Однако с вашим ответом вся информация об исходном часовом поясе будет забыта, что в примере нормально, но как только вы объедините данные из нескольких источников, я бы хотел, чтобы они где-то хранились. - person Timm; 20.08.2020
comment
@Timm: тем не менее, если вы знаете часовой пояс, зачем беспокоиться о хранении где-то смещений? И наоборот, если вы знаете только смещение UTC, вы не можете однозначно вывести конкретный часовой пояс, так зачем это волновать? ;-) - person MrFuppes; 20.08.2020
comment
Когда я сохраняю смещение в исходное время, я не могу создать DatetimeIndex при изменении смещения UTC. Когда я удаляю его, слияние данных из разных источников может / приведет к тому, что они будут либо выровнены с помощью sunrise / -set, либо я перейду к UTC и выровняю его по времени. Оба метода могут потребовать некоторого дополнительного ручного шага, если мне нужно другое представление, и я должен иметь эту информацию легко доступной. Я, наверное, переусердствовал с этим. Но я ужасно боюсь данных datetime в коде, они всегда где-то приводят к сбою. - person Timm; 21.08.2020
comment
@Timm: он всегда где-то приводит к сбою. - особенно в Python, есть некоторые подводные камни. Поскольку я не знаю подробностей вашей работы, мои мысли по этому поводу довольно общие, поймите меня правильно. Все, что я могу сказать по своему опыту, это то, что лучше всего хранить все в UTC внутри компании. Это позволяет избежать многих ошибок преобразования. Преобразуйте его в местное время, только если хотите, чтобы его прочитал человек, например для презентации, отображения на веб-странице или чего-то подобного. - person MrFuppes; 21.08.2020
comment
Я согласен, и сейчас этим занимаюсь. Я использовал ваше предложение с utc=True, выполните все операции в формате UTC, но сохраните смещение, чтобы можно было вернуться к удобному для человека выводу на основе часового пояса. - person Timm; 21.08.2020

Я не знаю, как использовать дату и время с учетом часового пояса в качестве индекса и получить индекс даты и времени в пандах. У меня есть предложение, которое может помочь в зависимости от того, что требуется от ваших данных.

Было бы приемлемо преобразовать объекты datetime в один и тот же часовой пояс, или информация о часовом поясе должна быть сохранена? Если вам нужен часовой пояс, но не обязательно с индексом, во время цикла по датам вы можете сохранить новый столбец со старым часовым поясом или иметь дубликат исходного времени из часового пояса в новом столбце, чтобы он все еще был доступен.

person Bradon Lodwick    schedule 19.08.2020