Pythonの日付処理まとめ|文字列変換・月末計算・前年同期比
/ 9 min read
Table of Contents
はじめに
会計や経理の仕事は、ほぼすべてが日付に紐づいています。月末、四半期末、決算日、前年同期。データを触るときも「当月末を求める」「前年の同じ月と比べる」といった処理が延々と出てきます。
この記事では、Python単体の datetime とpandasの両方で、日付処理の実務パターンをまとめました。特に月末の計算は間違えやすく、しかも間違えても普段は気づきにくいので、そこは重点的に書いています。
現在日時を取得して書式を整える
import datetime
dt_now = datetime.datetime.now()dt_now.strftime("%Y年%m月%d日 %H:%M:%S")# 2026年08月30日 10:00:00strftime() の書式は覚える必要はなく、よく使うのはこのあたりです。
| 書式 | 意味 | 出力例 |
|---|---|---|
%Y |
西暦4桁 | 2026 |
%m |
月(ゼロ埋め) | 08 |
%d |
日(ゼロ埋め) | 30 |
%b |
月の英語略称 | Aug |
%H:%M:%S |
時分秒 | 10:00:00 |
文字列を日付型に変える
会計システムやCSVから出てきた日付は、たいてい文字列です。strptime() で書式を教えて変換します。
import datetime
t = "May 26, 2022"t2 = datetime.datetime.strptime(t, "%b %d, %Y")# datetime.datetime(2022, 5, 26, 0, 0)
# 時刻が不要なら date 型にするt3 = t2.date()# datetime.date(2022, 5, 26)pandasなら列まるごと一発です。
import pandas as pd
df["date"] = pd.to_datetime(df["date"], format="%b %d, %Y")変換できない値が混ざっているとき
実務のデータには ― や空欄が平気で混ざります。errors="coerce" を付けると、変換できない値を NaT(日付版のNaN)にして処理を止めずに進められます。
df["date"] = pd.to_datetime(df["date"], errors="coerce")
# 変換できなかった行を確認するdf[df["date"].isna()]日付の加算・減算
日数の加算なら標準の timedelta で足りますが、月単位の加算には relativedelta が必要です。「1ヶ月後」は月によって28〜31日と長さが変わるためです。
$ pip install python-dateutilfrom datetime import datetimefrom dateutil.relativedelta import relativedelta
today = datetime.today()
# 年月日をそれぞれ取り出すyear, month, day = today.year, today.month, today.day
# n日の加算・減算today + relativedelta(days=3) # 3日後today + relativedelta(days=-3) # 3日前
# n月の加算・減算today + relativedelta(months=3) # 3ヶ月後today + relativedelta(months=-3) # 3ヶ月前
# 1年前の同じ日(前年同期の比較で使う)today + relativedelta(years=-1)月末を正しく求める
ここが本題です。「当月末」を求めるつもりで、次のように書くのは間違いです。
# NG: これは「1ヶ月後の前日」であって当月末ではないtoday + relativedelta(months=1, days=-1)2026年8月30日に実行すると 2026-09-29 が返ります。もっと分かりやすいのは2月で、2026年2月10日に実行すると 2026-03-09 になります。月末どころか翌月です。
正しくは、relativedelta の day(単数形) を使います。単数形の day は「その月の指定日にセットする。月の日数を超える場合は月末にクリップする」という挙動なので、day=31 と書けば常に当月末になります。
# OK: 常に当月末が返るtoday + relativedelta(day=31)| 実行日 | months=1, days=-1(誤) |
day=31(正) |
|---|---|---|
| 2026-08-30 | 2026-09-29 | 2026-08-31 |
| 2026-02-10 | 2026-03-09 | 2026-02-28 |
| 2024-02-10 | 2024-03-09 | 2024-02-29 |
うるう年も自動で処理されます。標準ライブラリだけで済ませたい場合は calendar を使います。
import calendarfrom datetime import date
y, m = 2026, 2last_day = calendar.monthrange(y, m)[1] # -> 28date(y, m, last_day) # -> 2026-02-28前月末・翌月末・期末日
月末の求め方さえ分かれば、応用は簡単です。
# 前月末today + relativedelta(months=-1, day=31)
# 翌月末today + relativedelta(months=1, day=31)
# 3月決算の期末日(当年の3月31日)today.replace(month=3) + relativedelta(day=31)pandasの列に対しては offsets を使うと素直に書けます。
import pandas as pd
# 各行の日付を、その月の月末に丸めるdf["月末"] = df["date"] + pd.offsets.MonthEnd(0)
# 四半期末に丸めるdf["四半期末"] = df["date"] + pd.offsets.QuarterEnd(0)MonthEnd(0) の 0 は「すでに月末ならそのまま」という意味です。1 にすると月末の日でも翌月末に飛ぶので、集計キーを作る用途では 0 を使います。
日付列の表示を YYYY/MM/DD に揃える
pd.to_datetime() した列をそのまま出力すると時分秒まで付いてきます。表示用に整えるには .dt.strftime() を使います。
df["date"] = pd.to_datetime(df["date"]).dt.strftime("%Y/%m/%d")前年同期比を計算する
月次の時系列データに前年比の列を足します。
| date | value |
|---|---|
| 2025-01-01 | 10 |
| 2025-02-01 | 20 |
| … | … |
| 2026-01-01 | 15 |
| 2026-02-01 | 40 |
pct_change() の periods に12を指定すると、12行前(=前年同月)との変化率が出ます。
df["前年比"] = df["value"].pct_change(periods=12)
# 最初の12ヶ月分はNaNになるのでゼロ埋めdf["前年比"] = df["前年比"].fillna(0)| date | value | 前年比 |
|---|---|---|
| 2025-01-01 | 10 | 0 |
| 2025-02-01 | 20 | 0 |
| … | … | … |
| 2026-01-01 | 15 | 0.5 |
| 2026-02-01 | 40 | 1.0 |
月が欠けている可能性があるデータなら、日付をインデックスにして asfreq() で月次に揃えてから計算すると確実です。
df = df.set_index("date").asfreq("MS") # MS = 月初基準df["前年比"] = df["value"].pct_change(periods=12).fillna(0)おわりに
日付処理は、間違えても例外が出ず、それらしい値が返ってくるのが厄介なところです。特に月末の計算は、月中に動かしているうちは誰も気づきません。決算や月次の締めに関わる処理を書いたときは、2月・うるう年・月末日の3パターンを通しておくと安心です。
