環境
- Python 3.11.2
- pandas 2.0.1
やりたいこと
文字列で表記された日時を、pandas.to_datetime関数でpandasのdatetimeオブジェクトに変換したいです。
ミリ秒のフォーマットは揃っていません。
data = [
"2023-01-01T15:58:12+09:00",
"2023-01-01T15:58:12.345+09:00",
]
起きたこと
pandas 1.5.3では以下のコードで、pandasのdatetimeオブジェクトに変換できました。
In [9]: pandas.to_datetime(data)
Out[9]: DatetimeIndex(['2023-01-01 15:58:12+09:00', '2023-01-01 15:58:12.345000+09:00'], dtype='datetime64[ns, pytz.FixedOffset(540)]', freq=None)
しかし、pandas 2.0.1ではValueError
が発生しました。
In [74]: pandas.to_datetime(data)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File ~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/pandas/_libs/tslibs/strptime.pyx:351, in pandas._libs.tslibs.strptime.array_strptime()
ValueError: time data "2023-01-01T15:58:12.345+09:00" doesn't match format "%Y-%m-%dT%H:%M:%S%z", at position 1. You might want to try:
- passing `format` if your strings have a consistent format;
- passing `format='ISO8601'` if your strings are all ISO8601 but not necessarily in exactly the same format;
- passing `format='mixed'`, and the format will be inferred for each element individually. You might want to use `dayfirst` alongside this.
原因
当然ではありますが、変数data
内の日時のフォーマットが異なるからです。
エラーメッセージを見ると、data[0]
から日時フォーマットを%Y-%m-%dT%H:%M:%S%z
だと推測して、date[1]
の2023-01-01T15:58:12.345+09:00
をパースしたことが分かります。
つまり、pandas2.0.1では以下のコードでもValueError
が発生します。
In [75]: pandas.to_datetime("2023-01-01T15:58:12.345+09:00", format="%Y-%m-%dT%H:%M:%S%z")
--------------------------------------------------------------------------
ValueError Traceback (most recent call last)
しかし、pandas 1.5.3ではエラーは発生しません。
In [15]: pandas.to_datetime("2023-01-01T15:58:12.345+09:00",format= "%Y-%m-%dT%H:%M:%S%z")
Out[15]: Timestamp('2023-01-01 15:58:12.345000+0900', tz='pytz.FixedOffset(540)')
この動きはpandas1.5.3のバグのようです。1
なお、Pythonのdatetimeモジュールではpandas2.0.1と同じ動きになります。
In [21]: datetime.datetime.strptime("2023-01-01T15:58:12.345+09:00", "%Y-%m-%dT%H:%M:%S%z")
---------------------------------------------------------------------------
ValueError: time data '2023-01-01T15:58:12.345+09:00' does not match format '%Y-%m-%dT%H:%M:%S%z'
解決策
pandas 2.0.0 からはfomat
引数にISO8601
を指定できます。
“ISO8601”, to parse any ISO8601 time string (not necessarily in exactly the same format);
format="ISO8601"
を指定すれば、ミリ秒のフォーマットが異なっていても(ミリ秒以外のフォーマットが異なっていても)pandasのdatetimeオブジェクトに変換できます。
In [78]: pandas.to_datetime(data, format="ISO8601")
Out[78]: DatetimeIndex(['2023-01-01 15:58:12+09:00', '2023-01-01 15:58:12.345000+09:00'], dtype='datetime64[ns, UTC+09:00]', freq=None)