0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

polarsでの日付型の処理:変換、差分、加算

0
Last updated at Posted at 2026-08-30

はじめに

この記事は、polarsで日付データを日付型に変換する方法、日付の差分(日単位、月単位、年単位)の取得、および加算した日付を取得する方法の備忘録です。
以下はサンプルデータになります。

import polars as pl # ver. 1.35.2

df = pl.DataFrame({
    "購入日_str": ["20001025", "19920221", "20251220"],
    "購入日_int": [20001025, 19920221, 20251220],
    
    "購入月_str": ["200010", "199202", "202512"],
    "購入月_int": [200010, 199202, 202512],
    
    "返品日_str": ["20011229", "19950430", None],
    "返品日_int": [20011229, 19950430, None],
})
print(df)

# shape: (3, 6)
# ┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
# │ 購入日_str ┆ 購入日_int ┆ 購入月_str ┆ 購入月_int ┆ 返品日_str ┆ 返品日_int │
# │ ---        ┆ ---        ┆ ---        ┆ ---        ┆ ---        ┆ ---        │
# │ str        ┆ i64        ┆ str        ┆ i64        ┆ str        ┆ i64        │
# ╞════════════╪════════════╪════════════╪════════════╪════════════╪════════════╡
# │ 20001025   ┆ 20001025   ┆ 200010     ┆ 200010     ┆ 20011229   ┆ 20011229   │
# │ 19920221   ┆ 19920221   ┆ 199202     ┆ 199202     ┆ 19950430   ┆ 19950430   │
# │ 20251220   ┆ 20251220   ┆ 202512     ┆ 202512     ┆ null       ┆ null       │
# └────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘

日付型への変換

日付がYYYYmmddYYYYmmの形の文字列型で入っているとき、以下のように.str.to_date()を使うことでpl.Date型に変換できます。
nullが含まれていてもエラーにはならず、そのままnullが返されます。
なお、YYYYmmのフォーマットの日付を.to_date("%Y%m")pl.Date型に変換したときは、YYYY-mm-dddd01になります。

df.select(
    pl.col("購入日_str").str.to_date("%Y%m%d"),
    pl.col("購入月_str").str.to_date("%Y%m"),
    
    pl.col("返品日_str").str.to_date("%Y%m%d"),
)

# shape: (3, 3)
# ┌────────────┬────────────┬────────────┐
# │ 購入日_str ┆ 購入月_str ┆ 返品日_str │
# │ ---        ┆ ---        ┆ ---        │
# │ date       ┆ date       ┆ date       │
# ╞════════════╪════════════╪════════════╡
# │ 2000-10-25 ┆ 2000-10-01 ┆ 2001-12-29 │
# │ 1992-02-21 ┆ 1992-02-01 ┆ 1995-04-30 │
# │ 2025-12-20 ┆ 2025-12-01 ┆ null       │
# └────────────┴────────────┴────────────┘

日付の型が整数などの数値型の場合は、.cast(str)で文字列型に変換してから.str.to_date()をします。

df.select(
    pl.col("購入日_int").cast(str).str.to_date("%Y%m%d"),
    pl.col("購入月_int").cast(str).str.to_date("%Y%m"),

    pl.col("返品日_int").cast(str).str.to_date("%Y%m%d"),
)

# shape: (3, 3)
# ┌────────────┬────────────┬────────────┐
# │ 購入日_int ┆ 購入月_int ┆ 返品日_int │
# │ ---        ┆ ---        ┆ ---        │
# │ date       ┆ date       ┆ date       │
# ╞════════════╪════════════╪════════════╡
# │ 2000-10-25 ┆ 2000-10-01 ┆ 2001-12-29 │
# │ 1992-02-21 ┆ 1992-02-01 ┆ 1995-04-30 │
# │ 2025-12-20 ┆ 2025-12-01 ┆ null       │
# └────────────┴────────────┴────────────┘

pl.Date型のYYYY-mm-ddddにあたる部分を月初にしたいときは.dt.month_start()、月末にしたいときは.dt.month_end()を呼び出します
月末にするときは、うるう年も考慮されます。

df.select(
     pl.col("購入日_str").str.to_date("%Y%m%d").alias("購入日"),
     pl.col("返品日_str").str.to_date("%Y%m%d").alias("返品日"),
).with_columns(
     pl.col("購入日").dt.month_start().alias("購入日_月初"),
     pl.col("購入日").dt.month_end().alias("購入日_月末"),

     pl.col("返品日").dt.month_start().alias("返品日_月初"),
     pl.col("返品日").dt.month_end().alias("返品日_月末"),        
)

# shape: (3, 6)
# ┌────────────┬────────────┬─────────────┬─────────────┬─────────────┬─────────────┐
# │ 購入日     ┆ 返品日     ┆ 購入日_月初 ┆ 購入日_月末 ┆ 返品日_月初 ┆ 返品日_月末 │
# │ ---        ┆ ---        ┆ ---         ┆ ---         ┆ ---         ┆ ---         │
# │ date       ┆ date       ┆ date        ┆ date        ┆ date        ┆ date        │
# ╞════════════╪════════════╪═════════════╪═════════════╪═════════════╪═════════════╡
# │ 2000-10-25 ┆ 2001-12-29 ┆ 2000-10-01  ┆ 2000-10-31  ┆ 2001-12-01  ┆ 2001-12-31  │
# │ 1992-02-21 ┆ 1995-04-30 ┆ 1992-02-01  ┆ 1992-02-29  ┆ 1995-04-01  ┆ 1995-04-30  │
# │ 2025-12-20 ┆ null       ┆ 2025-12-01  ┆ 2025-12-31  ┆ null        ┆ null        │
# └────────────┴────────────┴─────────────┴─────────────┴─────────────┴─────────────┘

ddの箇所を特定の日で統一したいときには、.str.to_date()の前段階で文字列として希望する日を結合しておきます。
YYYYmmddの8桁のフォーマットなら、前から6文字分を抜き出して、例えば'15'を結合してから.str.to_date()をします。

mid_of_month = '15'
df.select(
    (pl.col("購入日_str").str.head(6) + mid_of_month).str.to_date("%Y%m%d").alias("購入日_月中"),
    (pl.col("返品日_str").str.head(6) + mid_of_month).str.to_date("%Y%m%d").alias("返品日_月中"),
)

# shape: (3, 2)
# ┌─────────────┬─────────────┐
# │ 購入日_月中 ┆ 返品日_月中 │
# │ ---         ┆ ---         │
# │ date        ┆ date        │
# ╞═════════════╪═════════════╡
# │ 2000-10-15  ┆ 2001-12-15  │
# │ 1992-02-15  ┆ 1995-04-15  │
# │ 2025-12-15  ┆ null        │
# └─────────────┴─────────────┘

日付同士の差分の取得

以下に、pl.Date型同士の差を、年単位、月単位、日単位でそれぞれ取得する方法をまとめます。

  • 年単位:比較する日付について、.dt.year()で取得した年同士を引き算することで取得
  • 月単位:比較する日付について、.dt.year()で計算した年数差に12を掛けたのち、それに.dt.month()で取得した月同士の引き算の差分を足すことで取得
  • 日単位pl.Date型同士をそのまま引き算したのち、.dt.total_days()で取得
df.select(
    pl.col("購入日_str").str.to_date("%Y%m%d").alias("購入日"),
    pl.col("返品日_str").str.to_date("%Y%m%d").alias("返品日"),
).with_columns(
    (
        pl.col("返品日").dt.year() - pl.col("購入日").dt.year()
    ).alias("年数差"),

    (
        (pl.col("返品日").dt.year() - pl.col("購入日").dt.year()) * 12
        + (pl.col("返品日").dt.month() - pl.col("購入日").dt.month())
    ).alias("月数差"),

    (
        (pl.col("返品日") - pl.col("購入日")).dt.total_days()
    ).alias("日数差"),
)

# shape: (3, 5)
# ┌────────────┬────────────┬────────┬────────┬────────┐
# │ 購入日     ┆ 返品日     ┆ 年数差 ┆ 月数差 ┆ 日数差 │
# │ ---        ┆ ---        ┆ ---    ┆ ---    ┆ ---    │
# │ date       ┆ date       ┆ i32    ┆ i32    ┆ i64    │
# ╞════════════╪════════════╪════════╪════════╪════════╡
# │ 2000-10-25 ┆ 2001-12-29 ┆ 1      ┆ 14     ┆ 430    │
# │ 1992-02-21 ┆ 1995-04-30 ┆ 3      ┆ 38     ┆ 1164   │
# │ 2025-12-20 ┆ null       ┆ null   ┆ null   ┆ null   │
# └────────────┴────────────┴────────┴────────┴────────┘

月数差を求める計算が少し長いので、例えば次のような関数を実装しておくと便利です。

from typing import Literal

def get_diff_dates(
        date_col1: str, 
        date_col2: str, 
        units: Literal["y", "m", "d"]
    ) -> pl.Expr:
    if units == 'y':
        return (
            pl.col(date_col1).dt.year() - pl.col(date_col2).dt.year()
        )
    
    elif units == "m":
        return (
            (pl.col(date_col1).dt.year() - pl.col(date_col2).dt.year()) * 12
            + (pl.col(date_col1).dt.month() - pl.col(date_col2).dt.month())
        )

    elif units == "d":
        return (
            (pl.col(date_col1) - pl.col(date_col2)).dt.total_days()
        )

    else:
        raise ValueError('units must be one of ["y", "m", "d"]')

上記の関数を用いると、年数差や日数差などを同じ使用感で計算できます。

df.select(
    pl.col("購入日_str").str.to_date("%Y%m%d").alias("購入日"),
    pl.col("返品日_str").str.to_date("%Y%m%d").alias("返品日"),
).with_columns(
    get_diff_dates("返品日", "購入日", "y").alias("年数差"),
    get_diff_dates("返品日", "購入日", "m").alias("月数差"),
    get_diff_dates("返品日", "購入日", "d").alias("日数差"),
)

# shape: (3, 5)
# ┌────────────┬────────────┬────────┬────────┬────────┐
# │ 購入日     ┆ 返品日     ┆ 年数差 ┆ 月数差 ┆ 日数差 │
# │ ---        ┆ ---        ┆ ---    ┆ ---    ┆ ---    │
# │ date       ┆ date       ┆ i32    ┆ i32    ┆ i64    │
# ╞════════════╪════════════╪════════╪════════╪════════╡
# │ 2000-10-25 ┆ 2001-12-29 ┆ 1      ┆ 14     ┆ 430    │
# │ 1992-02-21 ┆ 1995-04-30 ┆ 3      ┆ 38     ┆ 1164   │
# │ 2025-12-20 ┆ null       ┆ null   ┆ null   ┆ null   │
# └────────────┴────────────┴────────┴────────┴────────┘

日付への加算

.dt.offset_by()を使うことで、特定の値を加算した日付を取得できます。
引数に、年ならy、月ならmo、日ならdの前に加算したい数字を付けます。
このとき、-をつけると数字分を引いた日付になります。
なお、月を意図してmとするとminutesになるので、moにするのを忘れないようにご注意ください。
それぞれの単位は、4y6mo5dのように組み合わせて利用できます。

df.select(
    pl.col("返品日_str").str.to_date("%Y%m%d").alias("返品日"),
).with_columns(
    pl.col("返品日").dt.offset_by("-2y").alias("2年前"),
    pl.col("返品日").dt.offset_by("3mo").alias("3ヶ月後"),
    pl.col("返品日").dt.offset_by("4y6mo5d").alias("4年6ヶ月5日後"),
)

# shape: (3, 4)
# ┌────────────┬────────────┬────────────┬───────────────┐
# │ 返品日     ┆ 2年前      ┆ 3ヶ月後    ┆ 4年6ヶ月5日後 │
# │ ---        ┆ ---        ┆ ---        ┆ ---           │
# │ date       ┆ date       ┆ date       ┆ date          │
# ╞════════════╪════════════╪════════════╪═══════════════╡
# │ 2001-12-29 ┆ 1999-12-29 ┆ 2002-03-29 ┆ 2006-07-04    │
# │ 1995-04-30 ┆ 1993-04-30 ┆ 1995-07-30 ┆ 1999-11-04    │
# │ null       ┆ null       ┆ null       ┆ null          │
# └────────────┴────────────┴────────────┴───────────────┘

以上です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?