Python で日付計算と言えば datetime
モジュールですね。まぁまぁ便利なんですが、標準では 月初 や 月末 を求めることができません。
なのでちょっとしたユーティリティコードとして書いておきました。
N ヶ月後・N ヶ月前
add_month()
は N ヶ月後の同日同時間 を求める関数です。同様に sub_month()
は N ヶ月前の同日同時間 を求めます。
2月31日 のように計算結果が存在しない日付になってしまう場合は、同月の末日を返します。
本当は datetime.timedelta
を使えれば良かったんですが、datetime.timedelta
では N ヶ月差を表現することはできないようです。
月初・月末
現在持っている日付の 月初 と 月末 を求める関数も書きました。
start_of_month()
は月初を、end_of_month()
は月末を返します。
コード
# -*- coding: utf-8 -*- from datetime import datetime from calendar import monthrange def add_month(_date, month_delta): """{month_delta} ヵ月後の同日の日時を返す >>> add_month(datetime.datetime(2017, 1, 30, 5, 20, 15), month_delta=1) datetime.datetime(2017, 2, 28, 23, 59, 59) >>> add_month(datetime.datetime(2017, 1, 15, 5, 20, 15), month_delta=1) datetime.datetime(2017, 2, 15, 5, 20, 15) >>> add_month(datetime.datetime(2017, 1, 30, 5, 20, 15), month_delta=13) datetime.datetime(2018, 2, 28, 23, 59, 59) """ year = _date.year month = _date.month day = _date.day hour = _date.hour minute = _date.minute second = _date.second microsecond = _date.microsecond alt_year = year alt_month = month + month_delta if alt_month > 12: month_overflow = alt_month alt_year += month_overflow // 12 alt_month = month_overflow % 12 elif alt_month <= 0: month_overflow = alt_month alt_year += (month_overflow - 1) // 12 alt_month = (month_overflow - 1) % 12 + 1 try: return datetime(alt_year, alt_month, day, hour, minute, second, microsecond) except ValueError: return end_of_month(datetime(alt_year, alt_month, 1, hour, minute, second, microsecond)) def sub_month(_date, month_delta): """{month_delta} ヵ月前の同日の日時を返す >>> sub_month(datetime.datetime(2017, 3, 30, 5, 20, 15), month_delta=1) datetime.datetime(2017, 2, 28, 23, 59, 59) >>> sub_month(datetime.datetime(2017, 3, 15, 5, 20, 15), month_delta=1) datetime.datetime(2017, 2, 15, 5, 20, 15) >>> sub_month(datetime.datetime(2017, 3, 20, 5, 20, 15), month_delta=5) datetime.datetime(2016, 10, 20, 5, 20, 15) """ return add_month(_date, -month_delta) def start_of_month(_date): """その月の月初の時を返す >>> start_of_month(datetime.datetime(2017, 3, 15)) datetime.datetime(2017, 3, 1, 0, 0) >>> start_of_month(datetime.datetime(2017, 2, 28, 10, 10, 10)) datetime.datetime(2017, 2, 1, 0, 0) """ year = _date.year month = _date.month return datetime(year, month, 1, 0, 0, 0) def end_of_month(_date): """その月の月末の日時を返す >>> end_of_month(datetime.datetime(2017, 3, 15)) datetime.datetime(2017, 3, 31, 23, 59, 59) >>> end_of_month(datetime.datetime(2017, 2, 28, 10, 10, 10)) datetime.datetime(2017, 2, 28, 23, 59, 59) """ year = _date.year month = _date.month end_of_month = monthrange(year, month)[1] return datetime(year, month, end_of_month, 23, 59, 59)
ちなみに、これらの関数名は PHP の良く出来た日付計算ライブラリ Carbon を大いに参考にしています。
一応、Gist があります。
Python で日時計算 ~ 月初とか月末とか N ヵ月前とか · GitHub
私からは以上です。