Python Pandas 時間処理の基本:dt.total_seconds の使い方

2025-05-27

pandas.Series.dt.total_seconds は、「pandas」の Series オブジェクトが datetime64[ns] 型または Timedelta[ns] 型のデータを持っている場合に利用できる属性の一つです。この属性を使うと、Series の各要素(日付や時間間隔)が表す総秒数を計算して、新しい Series として返してくれます。

具体的には、以下のようになります。

datetime64[ns] 型の場合

datetime64[ns] 型の Series に対して .dt.total_seconds() を適用すると、各要素(特定の日時)が紀元(1970年1月1日午前0時UTC)からの経過秒数として計算されます。

Timedelta[ns] 型の場合

Timedelta[ns] 型の Series に対して .dt.total_seconds() を適用すると、各要素(時間間隔)が持つ総秒数として計算されます。例えば、「1日と30分」という時間間隔であれば、(24times60times60)+(30times60)=86400+1800=88200 秒となります。

使い方の例

import pandas as pd

# datetime64[ns] 型の Series
dates = pd.Series(pd.to_datetime(['2025-05-16 00:00:00', '2025-05-16 00:00:30', '2025-05-17 01:00:00']))
seconds_from_epoch_dates = dates.dt.total_seconds()
print(seconds_from_epoch_dates)

出力例:

0    1.747373e+09
1    1.747373e+09
2    1.747460e+09
dtype: float64
# Timedelta[ns] 型の Series
time_diffs = pd.Series(pd.to_timedelta(['1 days', '0.5 days', '1 hours 30 minutes']))
total_seconds_diffs = time_diffs.dt.total_seconds()
print(total_seconds_diffs)
0    86400.0
1    43200.0
2     5400.0
dtype: float64


AttributeError: Can only use .dt accessor with datetimelike values (属性エラー: .dt アクセサは datetime ライクな値でのみ使用できます)

  • 解決策

    • まず、Series のデータ型を確認してください。Series.dtype で確認できます。
    • もしデータが日付や時間間隔を表す文字列などである場合は、pd.to_datetime()pd.to_timedelta() を使って適切なデータ型に変換してください。

    <!-- end list -->

    import pandas as pd
    
    # 間違った例: 文字列型の Series に .dt を使用
    string_dates = pd.Series(['2023-01-01', '2023-01-02'])
    # string_dates.dt.total_seconds()  # AttributeError が発生
    
    # 正しい例: pd.to_datetime() で変換
    datetime_series = pd.to_datetime(string_dates)
    seconds = datetime_series.dt.total_seconds()
    print(seconds)
    
    # 間違った例: 数値型の Series に .dt を使用
    numeric_times = pd.Series([10, 20, 30])
    # numeric_times.dt.total_seconds()  # AttributeError が発生
    
    # 正しい例: 時間間隔を表す場合は pd.to_timedelta() で変換
    timedelta_series = pd.to_timedelta(numeric_times, unit='seconds')
    total_seconds = timedelta_series.dt.total_seconds()
    print(total_seconds)
    
  • 原因
    このエラーは、.dt アクセサを datetime64[ns] 型または Timedelta[ns]ではない Series に対して使用しようとした場合に発生します。例えば、文字列型 (object)、整数型 (int64)、浮動小数点型 (float64) などの Series.dt.total_seconds() を適用しようとするとこのエラーが出ます。

TypeError: unsupported operand type(s) for -: 'Timestamp' and 'Timestamp' (型エラー: '-' のオペランドにサポートされていない型があります: 'Timestamp' と 'Timestamp')

  • 解決策

    • datetime64[ns] 型の Series の要素間の時間差(秒数)を計算したい場合は、まず Series の要素同士で差を取り(これにより Timedelta[ns] 型の Series が得られます)、その結果に対して .dt.total_seconds() を適用します。
    import pandas as pd
    
    dates = pd.Series(pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-04']))
    
    # 間違った例: datetime Series に直接 .dt.total_seconds() (要素間の差を意図した場合)
    # これは紀元からの秒数を返します
    seconds_from_epoch = dates.dt.total_seconds()
    print("紀元からの秒数:\n", seconds_from_epoch)
    
    # 正しい例: 要素間の時間差を計算する場合
    time_diff = dates.diff()
    seconds_diff = time_diff.dt.total_seconds()
    print("\n要素間の秒差:\n", seconds_diff)
    
  • 原因
    これは、datetime64[ns] 型の Series に対して .dt.total_seconds() を直接適用しようとした際に、内部的な計算で発生することがあります。datetime64[ns] 型の場合、.dt.total_seconds()紀元からの経過秒数を計算するため、要素同士の差を計算するような操作とは異なります。

予期せぬ NaN 値の発生

  • 解決策

    • SeriesNaTNaN が含まれていないか確認してください。Series.isnull()Series.isna() で確認できます。
    • 必要に応じて、fillna() メソッドを使って欠損値を適切な値で埋めるか、dropna() メソッドを使って欠損値を含む行や要素を削除することを検討してください。
    import pandas as pd
    import numpy as np
    
    time_diffs_with_na = pd.Series(pd.to_timedelta(['1 days', None, '2 hours', np.nan]))
    total_seconds_with_na = time_diffs_with_na.dt.total_seconds()
    print(total_seconds_with_na)
    
    # 欠損値を 0 で埋める例
    filled_seconds = time_diffs_with_na.dt.total_seconds().fillna(0)
    print("\n欠損値を 0 で埋めた結果:\n", filled_seconds)
    
    # 欠損値を削除する例
    dropped_seconds = time_diffs_with_na.dt.total_seconds().dropna()
    print("\n欠損値を削除した結果:\n", dropped_seconds)
    
  • 原因
    datetime64[ns] 型や Timedelta[ns] 型の SeriesNaT (Not a Time) や NaN (Not a Number) の値が含まれている場合、.dt.total_seconds() を適用した結果も対応する位置に NaN が生成されます。

タイムゾーンに関する注意点 (datetime64[ns, tz] 型の場合)

  • 解決策

    • 必要に応じて、.dt.tz_convert() メソッドを使って Series のタイムゾーンを目的のタイムゾーンに変換してから .dt.total_seconds() を適用してください。
    import pandas as pd
    import pytz
    
    dates_with_tz = pd.Series(pd.to_datetime(['2023-01-01 09:00:00', '2023-01-02 09:00:00'])).dt.tz_localize('Asia/Tokyo')
    utc_seconds = dates_with_tz.dt.total_seconds()
    print("UTC 基準の秒数:\n", utc_seconds)
    
    # アメリカ太平洋時間に変換してから秒数を計算
    pacific_tz = pytz.timezone('America/Los_Angeles')
    dates_pacific = dates_with_tz.dt.tz_convert(pacific_tz)
    pacific_seconds = dates_pacific.dt.total_seconds()
    print("\nアメリカ太平洋時間基準の秒数 (UTC 基準):\n", pacific_seconds)
    # 注意: .dt.total_seconds() は常に UTC 基準の紀元からの秒数を返します。
    # タイムゾーン変換は表示や他の計算に影響します。
    
  • 原因
    タイムゾーン情報を持つ datetime64[ns, tz] 型の Series に対して .dt.total_seconds() を適用すると、内部的には UTC (協定世界時) を基準とした紀元からの秒数が計算されます。もし特定のタイムゾーンでの秒数を期待している場合は、事前にタイムゾーンを変換する必要があります。



datetime64[ns] 型の Series から紀元からの総秒数を計算する例

この例では、日付と時間の情報を持つ Series を作成し、それぞれの要素が紀元(1970年1月1日午前0時UTC)から何秒経過したかを計算します。

import pandas as pd

# datetime64[ns] 型の Series を作成
dates = pd.Series(pd.to_datetime(['2025-05-16 09:00:00', '2025-05-17 12:30:00', '2025-05-18 18:45:30']))
print("元の日付と時間:\n", dates)
print("データ型:", dates.dtype)

# .dt.total_seconds() を適用して紀元からの総秒数を計算
seconds_from_epoch = dates.dt.total_seconds()
print("\n紀元からの総秒数:\n", seconds_from_epoch)
print("データ型:", seconds_from_epoch.dtype)

解説

  • dates.dt.total_seconds() を呼び出すことで、各 Timestamp オブジェクトが持つ紀元からの秒数が浮動小数点数 (float64) の Series として返されます。
  • pd.to_datetime() 関数を使って、文字列のリストを datetime64[ns] 型の Series に変換しています。

Timedelta[ns] 型の Series から総秒数を計算する例

この例では、時間間隔を表す Series を作成し、それぞれの時間間隔が合計で何秒になるかを計算します。

import pandas as pd

# Timedelta[ns] 型の Series を作成
time_diffs = pd.Series(pd.to_timedelta(['1 days 00:30:00', '0 days 02:15:45', '2 days 10:00:00']))
print("元の時間間隔:\n", time_diffs)
print("データ型:", time_diffs.dtype)

# .dt.total_seconds() を適用して総秒数を計算
total_seconds = time_diffs.dt.total_seconds()
print("\n総秒数:\n", total_seconds)
print("データ型:", total_seconds.dtype)

解説

  • time_diffs.dt.total_seconds() を呼び出すことで、各時間間隔が持つ総秒数が浮動小数点数 (float64) の Series として返されます。例えば、「1 days 00:30:00」は (1times24times60times60)+(0times60times60)+(30times60)+0=86400+1800=88200 秒となります。
  • pd.to_timedelta() 関数を使って、時間間隔を表す文字列のリストを Timedelta[ns] 型の Series に変換しています。

datetime64[ns] 型の Series の要素間の時間差を秒で計算する例

この例では、日付の Series を作成し、隣り合う要素間の時間差を秒単位で計算します。

import pandas as pd

# datetime64[ns] 型の Series を作成
event_times = pd.Series(pd.to_datetime(['2025-05-16 10:00:00', '2025-05-16 10:05:30', '2025-05-16 10:12:00']))
print("イベント発生時刻:\n", event_times)

# 差分を計算 (結果は Timedelta[ns] 型)
time_differences = event_times.diff()
print("\n時間差:\n", time_differences)
print("時間差のデータ型:", time_differences.dtype)

# 時間差を総秒数に変換
seconds_between_events = time_differences.dt.total_seconds()
print("\nイベント間の秒数:\n", seconds_between_events)
print("秒数のデータ型:", seconds_between_events.dtype)

解説

  • 得られた Timedelta[ns] 型の Series に対して .dt.total_seconds() を適用することで、各時間差が秒単位の浮動小数点数として得られます。
  • event_times.diff() を使うと、Series の隣り合う要素間の差が Timedelta[ns] 型の Series として計算されます。最初の要素は前の要素が存在しないため、差は NaT (Not a Time) になります。

タイムゾーン情報を持つ datetime64[ns, tz] 型の Series での扱い

タイムゾーン情報を持つ Series に対して .dt.total_seconds() を適用すると、内部的には UTC (協定世界時) を基準とした紀元からの秒数が計算されます。

import pandas as pd
import pytz

# タイムゾーン付きの datetime64[ns, tz] 型の Series を作成 (例: アメリカ太平洋時間)
dates_pst = pd.Series(pd.to_datetime(['2025-05-16 09:00:00', '2025-05-17 09:00:00'])).dt.tz_localize('America/Los_Angeles')
print("タイムゾーン付きの日付と時間:\n", dates_pst)
print("データ型:", dates_pst.dtype)

# .dt.total_seconds() を適用 (UTC 基準の紀元からの秒数)
utc_seconds_pst = dates_pst.dt.total_seconds()
print("\nUTC 基準の紀元からの総秒数:\n", utc_seconds_pst)
print("データ型:", utc_seconds_pst.dtype)

# 別のタイムゾーン (例: 日本時間) に変換してから秒数を計算
dates_jst = dates_pst.dt.tz_convert('Asia/Tokyo')
print("\n日本時間に変換した日付と時間:\n", dates_jst)
utc_seconds_jst = dates_jst.dt.total_seconds()
print("\n日本時間に変換後の UTC 基準の紀元からの総秒数:\n", utc_seconds_jst)
print("データ型:", utc_seconds_jst.dtype)
  • .dt.total_seconds() は、タイムゾーンに関わらず、UTC 基準の紀元からの秒数を返します。タイムゾーンの変換は、表示や他の時間計算に影響します。
  • .dt.tz_convert() を使うと、Series のタイムゾーンを別のタイムゾーンに変換できます。
  • .dt.tz_localize() を使って、Series にタイムゾーン情報を付与します。


datetime64[ns] 型の Series を数値型に変換して紀元からの秒数を取得する

datetime64[ns] 型の Series は、内部的にはナノ秒単位の整数として表現されています。これを秒単位に変換することで、.dt.total_seconds() と同様の結果を得ることができます。

import pandas as pd

dates = pd.Series(pd.to_datetime(['2025-05-16 09:00:00', '2025-05-17 12:30:00']))
print("元の日付と時間:\n", dates)

# 数値型 (ナノ秒) に変換
nanoseconds_from_epoch = dates.astype('int64')
print("\n紀元からのナノ秒:\n", nanoseconds_from_epoch)

# ナノ秒を秒に変換
seconds_from_epoch_alternative = nanoseconds_from_epoch / 1e9
print("\n紀元からの総秒数 (代替):\n", seconds_from_epoch_alternative)

# .dt.total_seconds() の結果と比較
seconds_from_epoch_original = dates.dt.total_seconds()
print("\n紀元からの総秒数 (オリジナル):\n", seconds_from_epoch_original)

print("\n両者の結果は一致:", (seconds_from_epoch_original == seconds_from_epoch_alternative).all())

解説

  • このナノ秒単位の値を 109 で割ることで、秒単位に変換できます。
  • dates.astype('int64') を使うと、datetime64[ns] 型の Series が紀元からの経過ナノ秒数を表す整数の Series に変換されます。

注意点
この方法は datetime64[ns] 型の Series にのみ適用できます。

Timedelta[ns] 型の Series を数値型に変換して総秒数を取得する

import pandas as pd

time_diffs = pd.Series(pd.to_timedelta(['1 days 00:30:00', '0 days 02:15:45']))
print("元の時間間隔:\n", time_diffs)

# 数値型 (ナノ秒) に変換
nanoseconds_diff = time_diffs.astype('int64')
print("\nナノ秒単位の時間差:\n", nanoseconds_diff)

# ナノ秒を秒に変換
total_seconds_alternative = nanoseconds_diff / 1e9
print("\n総秒数 (代替):\n", total_seconds_alternative)

# .dt.total_seconds() の結果と比較
total_seconds_original = time_diffs.dt.total_seconds()
print("\n総秒数 (オリジナル):\n", total_seconds_original)

print("\n両者の結果は一致:", (total_seconds_original == total_seconds_alternative).all())

解説

  • このナノ秒単位の値を 109 で割ることで、秒単位に変換できます。
  • time_diffs.astype('int64') を使うと、Timedelta[ns] 型の Series がナノ秒単位の時間差を表す整数の Series に変換されます。

手動で計算を行う (より複雑な場合や特定の要件がある場合)

より複雑な時間操作や、秒以外の単位で結果を得たい場合(例えば、特定の期間からの相対的な秒数など)、手動で計算を行うことも可能です。ただし、これは .dt.total_seconds() よりも複雑になることが多く、エラーも起こりやすいため、注意が必要です。

例えば、datetime64[ns] 型の Series の各要素を特定の日付からの経過秒数として計算したい場合は、以下のようにします。

import pandas as pd

dates = pd.Series(pd.to_datetime(['2025-05-16 10:00:00', '2025-05-16 10:05:30', '2025-05-16 10:12:00']))
reference_date = pd.to_datetime('2025-05-16 09:59:00')

# 各日付と基準日との時間差を計算
time_diff_from_reference = dates - reference_date
print("\n基準日からの時間差:\n", time_diff_from_reference)

# 時間差を総秒数に変換
seconds_from_reference_alternative = time_diff_from_reference.dt.total_seconds()
print("\n基準日からの経過秒数 (代替):\n", seconds_from_reference_alternative)
  • その後、.dt.total_seconds() を使って総秒数を計算します。
  • datetime64[ns] 型の Series 同士の減算は、Timedelta[ns] 型の Series を返します。
  • より複雑な時間計算や特定の基準日からの相対的な秒数を計算する場合は、Series 同士の演算と .dt アクセサを組み合わせて手動で計算を行うことができます。
  • Timedelta[ns] 型の Series の総秒数を取得する場合も、.astype('int64') / 1e9.dt.total_seconds() の代替となります。
  • datetime64[ns] 型の Series の紀元からの秒数を取得する場合、.astype('int64') / 1e9.dt.total_seconds() の代替となります。