質問
Python の標準ライブラリを使用して簡単に判断する方法はありますか (つまり、1 回の関数呼び出し) 指定された月の最終日?
標準ライブラリがこれをサポートしていない場合、dateutil パッケージはこれをサポートしますか?
解決
さっき見てたときは気付かなかった カレンダーモジュールのドキュメント, 、というメソッドですが、 月範囲 次の情報を提供します。
monthrange(年、月)
指定された年と月の月の最初の日の平日とその月の日数を返します。
>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)
それで:
calendar.monthrange(year, month)[1]
最も簡単な方法のようです。
ただ明確にします、 monthrange
閏年もサポートします:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
私の前回の答え まだ動作しますが、明らかに最適ではありません。
他のヒント
インポートしたくない場合は、 calendar
モジュールでは、単純な 2 ステップの関数を次のようにすることもできます。
import datetime
def last_day_of_month(any_day):
next_month = any_day.replace(day=28) + datetime.timedelta(days=4) # this will never fail
return next_month - datetime.timedelta(days=next_month.day)
出力:
>>> for month in range(1, 13):
... print last_day_of_month(datetime.date(2012, month, 1))
...
2012-01-31
2012-02-29
2012-03-31
2012-04-30
2012-05-31
2012-06-30
2012-07-31
2012-08-31
2012-09-30
2012-10-31
2012-11-30
2012-12-31
編集:よりクリーンなソリューションについては、@Blair Conrad の回答を参照してください。
>>> import datetime
>>> datetime.date (2000, 2, 1) - datetime.timedelta (days = 1)
datetime.date(2000, 1, 31)
>>>
編集:見る 私の他の答え. 。これよりも優れた実装がありますが、誰かが「独自の」計算機をどのように計算するかに興味がある場合に備えて、ここに残しておきます。
@John Millikin は良い答えを返しますが、翌月の初日の計算がさらに複雑になります。
以下は特に洗練されたものではありませんが、特定の日付が属する月の最終日を把握するには、次のことを試してみることができます。
def last_day_of_month(date):
if date.month == 12:
return date.replace(day=31)
return date.replace(month=date.month+1, day=1) - datetime.timedelta(days=1)
>>> last_day_of_month(datetime.date(2002, 1, 17))
datetime.date(2002, 1, 31)
>>> last_day_of_month(datetime.date(2002, 12, 9))
datetime.date(2002, 12, 31)
>>> last_day_of_month(datetime.date(2008, 2, 14))
datetime.date(2008, 2, 29)
これは実際には非常に簡単です dateutil.relativedelta
(pip 用のパッケージ python-datetutil)。 day=31
常に月の最終日を返します。
例:
from datetime import datetime
from dateutil.relativedelta import relativedelta
date_in_feb = datetime.datetime(2013, 2, 21)
print datetime.datetime(2013, 2, 21) + relativedelta(day=31) # End-of-month
>>> datetime.datetime(2013, 2, 28, 0, 0)
使用する relativedelta
次のように月の最後の日付を取得します。
from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)
アイデアは、月の最初の日を取得して使用することです。 relativedelta
1 か月前に進み、1 日前に戻ると、希望する月の最終日が得られます。
別の解決策は、次のようなことを行うことです。
from datetime import datetime
def last_day_of_month(year, month):
""" Work out the last day of the month """
last_days = [31, 30, 29, 28, 27]
for i in last_days:
try:
end = datetime(year, month, i)
except ValueError:
continue
else:
return end.date()
return None
そして、この関数を次のように使用します。
>>>
>>> last_day_of_month(2008, 2)
datetime.date(2008, 2, 29)
>>> last_day_of_month(2009, 2)
datetime.date(2009, 2, 28)
>>> last_day_of_month(2008, 11)
datetime.date(2008, 11, 30)
>>> last_day_of_month(2008, 12)
datetime.date(2008, 12, 31)
from datetime import timedelta
(any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)
>>> import datetime
>>> import calendar
>>> date = datetime.datetime.now()
>>> print date
2015-03-06 01:25:14.939574
>>> print date.replace(day = 1)
2015-03-01 01:25:14.939574
>>> print date.replace(day = calendar.monthrange(date.year, date.month)[1])
2015-03-31 01:25:14.939574
外部ライブラリを使用したい場合は、チェックしてください http://crsmithdev.com/arrow/
次のようにして月の最終日を取得できます。
import arrow
arrow.utcnow().ceil('month').date()
これにより、操作できる日付オブジェクトが返されます。
月の最後の日付を取得するには、次のようなことを行います。
from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
ここで何をしているのかを説明するために、2 つの部分に分けて説明します。
まず、使用する今月の日数を取得します。 月範囲 ブレア・コンラッドはすでにその解決策について言及しています。
calendar.monthrange(date.today().year, date.today().month)[1]
2 番目は最後の日付自体を取得することです。これは次の助けを借りて行います。 交換する 例えば
>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)
上で述べたようにそれらを組み合わせると、動的なソリューションが得られます。
import datetime
now = datetime.datetime.now()
start_month = datetime.datetime(now.year, now.month, 1)
date_on_next_month = start_month + datetime.timedelta(35)
start_next_month = datetime.datetime(date_on_next_month.year, date_on_next_month.month, 1)
last_day_month = start_next_month - datetime.timedelta(1)
私にとって、それが最も簡単な方法です。
selected_date = date(some_year, some_month, some_day)
if selected_date.month == 12: # December
last_day_selected_month = date(selected_date.year, selected_date.month, 31)
else:
last_day_selected_month = date(selected_date.year, selected_date.month + 1, 1) - timedelta(days=1)
最も簡単な方法 (カレンダーをインポートする必要がない) は、次の月の最初の日を取得し、そこから 1 日を引くことです。
import datetime as dt
from dateutil.relativedelta import relativedelta
thisDate = dt.datetime(2017, 11, 17)
last_day_of_the_month = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)
print last_day_of_the_month
出力:
datetime.datetime(2017, 11, 30, 0, 0)
追伸: このコードは、 import calendar
アプローチ;以下を参照してください:
import datetime as dt
import calendar
from dateutil.relativedelta import relativedelta
someDates = [dt.datetime.today() - dt.timedelta(days=x) for x in range(0, 10000)]
start1 = dt.datetime.now()
for thisDate in someDates:
lastDay = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)
print ('Time Spent= ', dt.datetime.now() - start1)
start2 = dt.datetime.now()
for thisDate in someDates:
lastDay = dt.datetime(thisDate.year,
thisDate.month,
calendar.monthrange(thisDate.year, thisDate.month)[1])
print ('Time Spent= ', dt.datetime.now() - start2)
出力:
Time Spent= 0:00:00.097814
Time Spent= 0:00:00.109791
このコードは、月の最終日の日付 (つまり、DD 部分だけでなく、YYYYMMDD 日付全体) が必要であることを前提としています。
Python 3.7には次のものがあります 文書化されていないもの calendar.monthlen(year, month)
関数:
>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28
終了日は自分で計算できます。単純なロジックは、来月の start_date から 1 日を引くことです。:)
したがって、カスタムメソッドを作成します。
import datetime
def end_date_of_a_month(date):
start_date_of_this_month = date.replace(day=1)
month = start_date_of_this_month.month
year = start_date_of_this_month.year
if month == 12:
month = 1
year += 1
else:
month += 1
next_month_start_date = start_date_of_this_month.replace(month=month, year=year)
this_month_end_date = next_month_start_date - datetime.timedelta(days=1)
return this_month_end_date
電話して、
end_date_of_a_month(datetime.datetime.now().date())
今月の終了日を返します。任意の日付をこの関数に渡します。その月の終了日を返します。
ここに別の答えがあります。追加のパッケージは必要ありません。
datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)
翌月の最初の日を取得し、そこから 1 日を引きます。
これは主な質問には答えていませんが、最後の質問を解決するための素晴らしいトリックが 1 つあります。 平日 1か月以内に使用することです calendar.monthcalendar
, これは、月曜日を最初の列として、日曜日を最後の列として編成された日付の行列を返します。
# Some random date.
some_date = datetime.date(2012, 5, 23)
# Get last weekday
last_weekday = np.asarray(calendar.monthcalendar(some_date.year, some_date.month))[:,0:-2].ravel().max()
print last_weekday
31
全体 [0:-2]
重要なのは、週末のコラムを削り取って廃棄することです。月外の日付は 0 で示されるため、max は事実上それらを無視します。
の用法 numpy.ravel
厳密には必要ありませんが、私はそれに依存するのが嫌いです。 単なる慣例 それ numpy.ndarray.max
どの軸で計算するかを指定しないと、配列が平坦化されます。
パンダを使おう!
def isMonthEnd(date):
return date + pd.offsets.MonthEnd(0) == date
isMonthEnd(datetime(1999, 12, 31))
True
isMonthEnd(pd.Timestamp('1999-12-31'))
True
isMonthEnd(pd.Timestamp(1965, 1, 10))
False
私はこの方法の方が好きです
import datetime
import calendar
date=datetime.datetime.now()
month_end_date=datetime.datetime(date.year,date.month,1) + datetime.timedelta(days=calendar.monthrange(date.year,date.month)[1] - 1)
独自の小さな関数を作成したい場合は、これが良い出発点になります。
def eomday(year, month):
"""returns the number of days in a given month"""
days_per_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
d = days_per_month[month - 1]
if month == 2 and (year % 4 == 0 and year % 100 != 0 or year % 400 == 0):
d = 29
return d
このためには、うるう年のルールを知っておく必要があります。
- 4年ごとに
- 100年ごとを除いて
- しかしまた400年ごとに
相対デルタを使用できますhttps://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
それがあなたに最後の日を与えるでしょう。
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
出力:
31
これにより、現在の月の最終日が出力されます。この例では、2016 年 5 月 15 日でした。したがって、出力は異なる場合がありますが、出力は現在の月と同じ日数になります。毎日 cron ジョブを実行して月の最終日を確認したい場合に最適です。
それで:
import calendar
from time import gmtime, strftime
lastDay = calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
today = strftime("%d", gmtime())
lastDay == today
出力:
False
月の最終日でない限り。
日付範囲を渡す場合は、これを使用できます。
def last_day_of_month(any_days):
res = []
for any_day in any_days:
nday = any_day.days_in_month -any_day.day
res.append(any_day + timedelta(days=nday))
return res
以下のコードでは 「月の最終日を取得(dt)」 これは、「YYYY-MM-DD」のような文字列形式の日付とともに表示されます。
import datetime
def DateTime( d ):
return datetime.datetime.strptime( d, '%Y-%m-%d').date()
def RelativeDate( start, num_days ):
d = DateTime( start )
return str( d + datetime.timedelta( days = num_days ) )
def get_first_day_of_month( dt ):
return dt[:-2] + '01'
def get_last_day_of_month( dt ):
fd = get_first_day_of_month( dt )
fd_next_month = get_first_day_of_month( RelativeDate( fd, 31 ) )
return RelativeDate( fd_next_month, -1 )
これはソリューションベースのPythonラムダです:
next_month = lambda y, m, d: (y, m + 1, 1) if m + 1 < 13 else ( y+1 , 1, 1)
month_end = lambda dte: date( *next_month( *dte.timetuple()[:3] ) ) - timedelta(days=1)
の next_month
lambda は翌月の初日のタプル表現を見つけて、翌年にロールオーバーします。の month_end
ラムダは日付を変換します (dte
) をタプルに適用します next_month
そして新しい日付を作成します。その場合、「月末」とは、翌月の初日からその日を引いたものになります。 timedelta(days=1)
.
とても便利だと思います。この方法で試してみてください。いくつかのパッケージをインポートする必要があります。
import time
from datetime import datetime, date
from datetime import timedelta
from dateutil import relativedelta
start_date = fields.Date(
string='Start Date',
required=True,
)
end_date = fields.Date(
string='End Date',
required=True,
)
_defaults = {
'start_date': lambda *a: time.strftime('%Y-%m-01'),
'end_date': lambda *a: str(datetime.now() + relativedelta.relativedelta(months=+1, day=1, days=-1))[:10],
}
私には簡単な解決策があります:
import datetime
datetime.date(2012,2, 1).replace(day=1,month=datetime.date(2012,2,1).month+1)-timedelta(days=1)
datetime.date(2012, 2, 29)