業務系のシステム作ると必ず出てくる「前月同日」「前月末日」。
ちょくちょく使いそうなのでメモ。
前月同日
先日悩んでいた所、素敵な助言をいただきました。
というわけで、 dateutil を使用。
このライブラリ、日付計算以外にもタイムゾーンの指定も楽だったりして、かなりの神ライブラリです。
>>> import datetime >>> from dateutil import relativedelta >>> now = datetime.datetime.now() >>> now datetime.datetime(2011, 8, 14, 15, 2, 48, 6994) >>> now - relativedelta.relativedelta(months=1) datetime.datetime(2011, 7, 14, 15, 2, 48, 6994)
ちなみに、3月31日などの前月同日が存在しない場合、
民法 第143条第2項(暦による期間の計算)
週、月又は年の初めから期間を起算しないときは、その期間は、最後の週、月又は年においてその起算日に応当する日の前日に満了する。ただし、月又は年によって期間を定めた場合において、最後の月に応当する日がないときは、その月の末日に満了する。
民法第143条第2項(暦による期間の計算)
との事で、これもまた dateutil は対応出来てます。
>>> import datetime >>> from dateutil import relativedelta >>> datetime.datetime(2011, 3, 31) - relativedelta.relativedelta(months=1) datetime.datetime(2011, 2, 28, 0, 0)
まさに神。
前月末日
前月同日から応用して、前月末日。
>>> import datetime >>> import calendar >>> from dateutil import relativedelta >>> now = datetime.datetime.now() >>> now datetime.datetime(2011, 8, 14, 16, 48, 29, 526716) >>> last = now - relativedelta.relativedelta(months=1) >>> last datetime.datetime(2011, 7, 14, 16, 48, 29, 526716) >>> weekday, last_day = calendar.monthrange(last.year, last.month) >>> weekday, last_day (4, 31) >>> last_date = datetime.datetime(last.year, last.month, last_day) >>> last_date datetime.datetime(2011, 7, 31, 0, 0)
これはもうちょっと上手く出来そうかな…?
ちなみに、calendar.monthrange(year, month) は指定した年月の1日の曜日と末日を求めるメソッド。
関数化して、その辺に置いとけば便利に使えそう。
import datetime import calendar from dateutil import relativedelta def last_date(year, month, day): now = datetime.datetime(year, month, day) return now - relativedelta.relativedelta(months=1) def last_day(year, month): last = last_date(year, month, 1) end_day = calendar.monthrange(last.year, last.month)[1] return datetime.datetime(last.year, last.month, end_day)
>>> last_date(2011, 8, 15) datetime.datetime(2011, 7, 15, 0, 0) >>> last_day(2011, 8) datetime.datetime(2011, 7, 31, 0, 0)
教えて頂いた Ian さんに多大なる感謝を捧げます!