PySparkにおける日付時刻とTime Zone

に公開

概要

PySparkで日付時刻を扱う際の注意点

  • 日付時刻型にはTimestampTypeとTimestampNTZTypeがある。
  • Sparkセッションのタイムゾーン設定が挙動に影響するため明示的に設定した方がよい。
  • 日付時刻文字列は意図しない変換を避けるためタイムゾーン情報をつけた方がよい。
  • Pandasとの変換では意図しない変換を避けるためタイムゾーン情報をつけた方がよい。
  • 公式ドキュメントにある程度記述がありますが、undocumentedな挙動も多いです。

2種類の日付時刻型

  • TimestampType
    • Sparkセッションのタイムゾーン設定 (spark.sql.session.timeZone) の影響を受けます。
  • TimestampNTZType
    • タイムゾーン情報を持たないため、Sparkセッションのタイムゾーン設定の影響を受けません。

Sparkセッションのタイムゾーン設定 (spark.sql.session.timeZone)

  • この設定は以下の挙動に影響します。
    • TimestampTypeの値を文字列として表示する際のタイムゾーン。
    • タイムゾーン情報を含まない文字列(例: "2025-04-08 18:00:00")を TimestampType に変換する際の解釈。セッションタイムゾーンの時刻として解釈されます。
    • current_timestamp() や now() といった現在時刻を返す関数の結果のタイムゾーン。
    • hour(), minute(), date_format() など、TimestampType から日付/時刻要素を抽出する関数の結果。
    • Spark DataFrame を Pandas DataFrame や Arrow Table に変換する際の TimestampType の扱い(UTCに正規化される際の基準タイムゾーンとして使用されます)。
  • デフォルトはJVMのタイムゾーンです。
  • 明示的に設定しておくとよいです。
    • spark.conf.set("spark.sql.session.timeZone", "Asia/Tokyo")
  • 設定の確認
    • spark.conf.get("spark.sql.session.timeZone")
  • 分散環境では各ノードの設定が異なる可能性があるため、理想的にはすべてのノードで明示的に設定しておいた方がよいようです。

文字列との変換

  • タイムゾーン情報付き文字列
    • "2025-04-08T18:00:00+09:00" のようなISO 8601形式の文字列をTimestampTypeにキャストする場合、文字列内のタイムゾーン情報が優先され、正しくUTCに変換されて格納されます。セッションタイムゾーン設定の影響は受けません。
  • タイムゾーン情報なし文字列
    • "2025-04-08 18:00:00"のような文字列を TimestampType にキャストする場合、セッションタイムゾーンの時刻として解釈されます。
  • TimestampNTZTypeへのキャストでは、タイムゾーン情報は無視され、文字列の時刻がそのまま解釈されます。
  • 意図しない変換を避けるためにタイムゾーン情報をつけた方がよいです。

Pandasとの変換

  • PySpark → Pandas (toPandas()pandas_udf呼び出し)
    • PySparkのTimestampTypeはセッションタイムゾーンに従ってローカル時刻に変換され、Pandasのdatetime64[ns]に変わります。
  • Pandas → PySpark (createDataFrame()pandas_udfの返り値)
    • datetime64[ns]が渡されるとUTCとして解釈されます。
    • datetime64[ns, tz]はUTCに変換してからPySparkに渡されます。
  • 意図しない変換を避けるためにタイムゾーン情報をつけた方がよいです。

まとめ

  • Sparkセッションのタイムゾーン設定を明示的に設定した方がよい。
  • 文字列でもPandasでもタイムゾーン情報をつけた方がよい。

Discussion