为何无时区Timestamp拼接转整数,带时区则保留?求解决方法
pandas无时区DatetimeIndex拼接问题解析
符合预期(带时区)的示例
import datetime import numpy as np import pandas as pd aware = pd.DatetimeIndex(["2024-11-21", "2024-11-21 12:00"], tz="UTC") eod = datetime.datetime.combine(aware[-1].date(), datetime.time.max, aware.tz) aware, eod, np.concat([aware, [eod]])
返回结果:
(DatetimeIndex(['2024-11-21 00:00:00+00:00', '2024-11-21 12:00:00+00:00'], dtype='datetime64[ns, UTC]', freq=None), datetime.datetime(2024, 11, 21, 23, 59, 59, 999999, tzinfo=datetime.timezone.utc), array([Timestamp('2024-11-21 00:00:00+0000', tz='UTC'), Timestamp('2024-11-21 12:00:00+0000', tz='UTC'), datetime.datetime(2024, 11, 21, 23, 59, 59, 999999, tzinfo=datetime.timezone.utc)], dtype=object))
注意:np.concat返回的数组中包含Timestamp对象和一个datetime对象,格式符合预期。
不符合预期(无时区)的示例
naive = pd.DatetimeIndex(["2024-11-21", "2024-11-21 12:00"]) eod = datetime.datetime.combine(naive[-1].date(), datetime.time.max) naive, eod, np.concat([naive, [eod]])
返回结果:
(DatetimeIndex(['2024-11-21 00:00:00', '2024-11-21 12:00:00'], dtype='datetime64[ns]', freq=None), datetime.datetime(2024, 11, 21, 23, 59, 59, 999999), array([1732147200000000000, 1732190400000000000, datetime.datetime(2024, 11, 21, 23, 59, 59, 999999)], dtype=object))
注意:np.concat返回的数组中出现了整数(纳秒级时间戳数值)和一个datetime对象,不符合预期格式。
提出的问题
- 为何无时区索引拼接后的数组会出现整数?
- 如何避免该问题?即如何将当日结束时间(EOD)追加到无时区
DatetimeIndex?
补充说明
有趣的是,在numpy层面,带时区和无时区索引的底层存储数值完全一致:
np.testing.assert_array_equal(aware.values, naive.values)
问题解答
1. 无时区索引拼接出现整数的原因
这是因为无时区DatetimeIndex底层存储的是datetime64[ns]类型的数值,当用np.concat直接拼接它和Python原生datetime对象时,numpy无法找到能同时兼容这两种类型的通用格式,会触发类型降级:将datetime64[ns]转换为对应的纳秒级整数时间戳,而原生datetime对象保持不变,最终得到object类型数组,其中混杂了整数和datetime对象。
而带时区的DatetimeIndex元素是带时区的Timestamp对象,numpy拼接时会保留所有元素为对象类型,不会触发数值转换,因此结果中是Timestamp和datetime对象的组合。
2. 避免问题的解决方法
不要用np.concat处理DatetimeIndex和原生datetime的拼接,改用pandas自身的方法保证类型统一:
方法一:将原生datetime转为Timestamp后追加
import datetime import pandas as pd naive = pd.DatetimeIndex(["2024-11-21", "2024-11-21 12:00"]) eod = datetime.datetime.combine(naive[-1].date(), datetime.time.max) # 转换为pandas Timestamp eod_ts = pd.Timestamp(eod) # 用append方法生成新索引 new_index = naive.append(pd.DatetimeIndex([eod_ts])) print(new_index)
输出:
DatetimeIndex(['2024-11-21 00:00:00', '2024-11-21 12:00:00', '2024-11-21 23:59:59.999999'], dtype='datetime64[ns]', freq=None)
方法二:直接用pandas构造当日结束时间
import pandas as pd naive = pd.DatetimeIndex(["2024-11-21", "2024-11-21 12:00"]) # 直接构造当日最后一刻的Timestamp eod_ts = pd.Timestamp(naive[-1].date()) + pd.Timedelta(days=1) - pd.Timedelta(microseconds=1) new_index = naive.append(pd.DatetimeIndex([eod_ts])) print(new_index)
输出同上。
方法三:用pd.concat处理DatetimeIndex对象
import datetime import pandas as pd naive = pd.DatetimeIndex(["2024-11-21", "2024-11-21 12:00"]) eod = datetime.datetime.combine(naive[-1].date(), datetime.time.max) # 把eod包装成DatetimeIndex后拼接 new_index = pd.concat([naive, pd.DatetimeIndex([eod])]) print(new_index)
输出同上。
以上方法都能保证最终得到统一类型的DatetimeIndex,不会出现整数数值。
内容的提问来源于stack exchange,提问作者sds
相关产品推荐
相关产品推荐

