从 DST 感知日期时间对象在 Dataframe 中创建 pandas DatetimeIndex

Creating pandas DatetimeIndex in Dataframe from DST aware datetime objects

从网上 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/non-DST 一切正常,而且,我得到一个带有 DatetimeIndex 的数据框,我以后可以继续工作。 但是,一旦两个不同的时间偏移量出现在一个数据集中(上例),我的数据框中只会得到一个 Index,它不支持任何基于时间的方法。

有什么方法可以让 pandas 接受时区感知、不同日期作为索引?

我不知道使用时区感知日期时间作为索引并在 pandas 中获取日期时间索引的方法。不过,我确实有一个建议可能会有所帮助,具体取决于您对数据的要求。

将日期时间对象转换为同一时区是否可以接受,或者时区信息是否必须保留?如果您确实需要时区但不一定需要索引,在循环遍历日期时,您可以使用旧时区存储一个新列,或者在新列中复制时区的原始时间,以便仍然可以访问它。

  • A pandas datetime 列也要求偏移量相同。具有不同偏移量的列将不会转换为 datetime dtype。
  • 我建议,不要将数据转换为日期时间,直到它处于 pandas
  • 把时间偏移分开,当作一个timedelta
  • to_timedelta 要求格式为 'hh:mm:ss' 所以在 offset
  • 末尾添加 ':00'
  • 有关所有可用的时间增量操作,请参阅 Pandas: Time deltas
  • pandas.Series.dt.tz_convert
  • pandas.Series.tz_localize
  • 通过以下方式转换为特定的 TZ:
    • 如果日期时间不是 datetime64[ns, UTC] dtype,则在 .dt.tz_convert('US/Pacific')
    • 之前先使用 .dt.tz_localize('UTC')
    • 否则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]

其他资源

问题措辞的小修正(我认为这很重要)。您拥有的是 UTC 偏移量 - DST/no-DST 需要 更多 信息,即时区。在这里,这很重要,因为您可以轻松地将具有 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,所以我会接受的。但是,如果您确实需要某个时区的日期时间,则可以转换为例如作为

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)