【Python】月初め、月末の取得方法 ー訂正ー

月間データ分析をするための、月初めと月末の取得方法。

datetime型の場合

import datetime
import calendar

today = datetime.date.today()
first_day=today.replace(day=1)
eom = first_day.replace(day=calendar.monthrange(first_day.year, first_day.month)[1])
print(first_day,eom)

## 結果 ##
2022-09-01 2022-09-30

timezone.now()を使う場合。

from django.utils import timezone

today = timezone.now()
t = today.replace(day=1, hour=0, minute=0, second=0)
first_day = datetime.datetime(t.year, t.month, t.day, 0, 0, 0, 0,
                        tzinfo=datetime.timezone(datetime.timedelta(hours=9)))  #月始め
eom = first_day.replace(day=calendar.monthrange(first_day.year, first_day.month)[1])
print(first_day,eom)

## 結果 ##
2022-09-01 00:00:00+09:00 2022-09-30 00:00:00+09:00

一応上手くいくが、月末の時間が 23:59:59+09:00 になってほしいので、更に追加。(この部分を訂正しました(文末))

today = timezone.now()
t = today.replace(day=1, hour=0, minute=0, second=0)
first_day = datetime.datetime(t.year, t.month, t.day, 0, 0, 0, 0,
                            tzinfo=datetime.timezone(datetime.timedelta(hours=9))) #月始め
eom = first_day.replace(day=calendar.monthrange(first_day.year, first_day.month)[1])

eom1 = eom + datetime.timedelta(days=1)   ## 追加
eom2 = eom1 - datetime.timedelta(seconds=1) ## 追加

## 結果 ##
# first_day : 2022-09-01 00:00:00+09:00 
# eom : 2022-09-30 00:00:00+09:00
# eom1 : 2022-10-01 00:00:00+09:00
# eom2 : 2022-09-30 23:59:59+09:00

## 一行で書くとこうなります。
## eom = first_day.replace(day=calendar.monthrange(first_day.year, first_day.month)[1])  + datetime.timedelta(days=1)  - datetime.timedelta(seconds=1)

追記:2022/09/13 22:10

更に別の方法が見つかったので、追記します。

月単位で絞り込みをする場合、以下のようなシンプルなものでもOK。月初め、月末を求める必要がないので楽です。

Sample.objects.filter(date__year = '2022', 
                      date__month = '09')

先に書いた方法で、月初め、月末を求めて絞り込みをする場合は、以下のように書くことができます。

Sample.objects.filter(date__range = [first_day, eom])
Sample.objects.filter(date__gte = first_day, date__lte = eom ])

訂正記事

today = timezone.now()

t = today.replace(day=1, hour=0, minute=0, second=0)
this_month = datetime.datetime(t.year, t.month, t.day, 0, 0, 0, 0,
                              tzinfo=datetime.timezone(datetime.timedelta(hours=9)))  # 今月1日のタイムゾーン付き

last_month = this_month.replace(month=t.month - 1) # 先月1日

## this_month 含まない絞り込み。
sample = Sample.objects.filter(dt__gte=last_month, dt__lt=this_month) 

## this_month を含む絞り込み。
sample = Sample.objects.filter(dt__range=[last_month, this_month])

## または、
sample = Sample.objects.filter(dt__gte=last_month, dt__lte=this_month) 

この方法では、最初の t の day を、例えば10に設定すると、先月の10日から今月の10日の間で絞り込むことが出来ます。

ただし、1月の場合、1月から1を引くことはできないので、if文で切り分けます。

if t.month !=1:
    last_month = this_month.replace(month=t.month - 1)
else:
    last_month = this_month.replace(year=t.year - 1, month=12)

度々の訂正、失礼しました。

参考記事

【Python】今月の集計をしたい時に使う月初の取得方法

Python, datetime, pytzでタイムゾーンを設定・取得・変換・削除

How do I filter query objects by date range in Django?

お薦め