【Python】日付列の誤変換と時差の混在を検出する

PythonのTopに戻る

日付列は、既知の書式とタイムゾーンの規則を指定して変換し、失敗した文字列を元の列と一緒に残す。時差付きのログはUTCへそろえると同じ時点を比較できるが、時差情報のない文字列へutc=Trueを付けるだけでは、現地時刻を正しく解釈したことにならない。

最小例で確かめる

以下は説明用に作った小さなデータである。実測データや実行速度の測定結果ではない。コード全体をexample.pyとして保存すれば、入力ファイルを別途用意せずに実行できる。assertは、この例で成り立つべき形や値を確認するために入れてある。

import pandas as pd
raw = pd.Series(["2026-01-01T09:00:00+09:00",
                 "2026-01-01T00:00:00+00:00",
                 "2026-02-30T00:00:00+00:00", None], dtype="string")
parsed = pd.to_datetime(raw, format="%Y-%m-%dT%H:%M:%S%z",
                        errors="coerce", utc=True)
failed = raw.notna() & parsed.isna()
print("UTC:", [str(v) for v in parsed.iloc[:2]])
print("invalid input:", raw[failed].tolist())
local_raw = pd.Series(["2026-01-01 09:00:00"])
local = pd.to_datetime(local_raw, format="%Y-%m-%d %H:%M:%S")
tokyo_utc = local.dt.tz_localize("Asia/Tokyo").dt.tz_convert("UTC")
print("Tokyo converted:", str(tokyo_utc.iloc[0]))
dst = pd.DatetimeIndex(["2026-11-01 01:30", "2026-03-08 02:30"])
dst_checked = dst.tz_localize("America/New_York", ambiguous="NaT",
                               nonexistent="NaT")
print("DST unresolved:", dst_checked.isna().tolist())
assert parsed.iloc[0] == parsed.iloc[1] == tokyo_utc.iloc[0]
assert failed.tolist() == [False, False, True, False]
assert str(parsed.dtype) == "datetime64[ns, UTC]"
assert dst_checked.isna().all()

実行結果

UTC: ['2026-01-01 00:00:00+00:00', '2026-01-01 00:00:00+00:00']
invalid input: ['2026-02-30T00:00:00+00:00']
Tokyo converted: 2026-01-01 00:00:00+00:00
DST unresolved: [True, True]

解析できない日付を一覧にする

formatは期待する入力書式を表す。この例では年月日、T、時分秒、時差という形式に限定している。存在しない2月30日はNaTとなるが、元から欠測だったNoneと区別するため、raw.notna()とparsed.isna()を組み合わせて失敗マスクを作った。解析後のNaTだけを見ると、この違いが消えてしまう。

月日順が曖昧な01/02のような値を自動推定へ任せると、入力元の規則と違う日付になる可能性がある。複数の既知の形式が混在するなら、入力元や形式ごとに分けて明示的に変換する方が原因を追いやすい。都合よく読めるまでformatを緩める前に、何を正しい書式とするかを確定する。

時差付きの時刻をUTCへそろえる

最初の二つの文字列は見た目の時刻が9時間違うが、同じ時点を表している。utc=Trueによって時差付き入力がUTCへ変換され、比較可能な一つの日時型になる。単に時差文字列を削って時刻部分だけを比べると、この一致を失う。

UTCへ統一した列は処理や結合に向いている。表示を現地時間にしたい場合は、保存している時点を変えずにtz_convertで表示先のタイムゾーンへ変換する。日時の値と文字列の表示は別なので、報告書にはどのタイムゾーンで表しているかも記しておこう。

時差なし入力には地域を与える

時差のない2026-01-01 09:00:00が東京の時刻なら、まず書式で解析し、tz_localize(“Asia/Tokyo”)で東京の現地時刻として意味付けする。その後にtz_convert(“UTC”)で同じ時点をUTCへ変換する。localizeは地域の割り当て、convertは既に地域を持つ時刻の変換である。

時差なし入力へutc=Trueを付けると、それをUTCの時刻として扱うため、東京の9時を表していた入力なら9時間ずれた時点になる。入力元のタイムゾーンが不明なら、その情報を補う必要がある。機械の実行場所や担当者の現在地から推測して変換するべきではない。

夏時間と日付境界にも注意する

夏時間の切替では、同じ現地時刻が2回現れる場合と、存在しない現地時刻ができる場合がある。例ではニューヨークの曖昧時刻と存在しない時刻をNaTとして保留した。shift_forwardなどで移動する方法もあるが、元ログの時点を変更することになるので、採用する規則を明示してから使う。

UTCへ変換すると現地の日付と違う日付になることもある。日別集計をどちらの地域の日付で行うかにより、グループ分けが変わる。変換失敗件数、NaT、日時型、同じ時点を表す既知の例を確かめたうえで、日付境界のデータも点検する。タイムゾーン規則の更新が関係する処理では、使用環境の情報も残すと再確認しやすい。

動作確認環境と参考資料

Linux・CPython 3.12.14、NumPy 2.3.5、pandas 2.2.3、SciPy 1.17.0、Matplotlib 3.10.8の環境で掲載コードを実行した。使用するライブラリはコード冒頭のimportを参照してほしい。公式資料の最新版と、この実行確認版は区別している。数値の末尾や表の表示幅は環境によって変わることがある。

関連するTips

PythonのTopに戻る