Check if it is the end of the month in python
Question:
I am writing code to take data from the last year. I want to round up the earlier date like so: If it is July 14 2015, I want data from August 1st 2014-July 14,2015
df = pd.read_csv('MyData.csv')
df['recvd_dttm'] = pd.to_datetime(df['recvd_dttm'])
range_max = datetime.datetime.now()
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)+ pd.tseries.offsets.MonthEnd(1) + pd.tseries.offsets.DateOffset(days=1)
if datetime.datetime.now() == is_month_end:
# take slice with final week of data
df = df[(df['recvd_dttm'] >= range_min) &
(df['recvd_dttm'] <= range_max)]
My problem is that when it is July 31, 2015, my code goes to the end of the next month, essentially cutting out an entire month.
I am trying to make a for loop to fix this problem.
If it is the end of the month:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)
else:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)+ pd.tseries.offsets.MonthEnd(1) + pd.tseries.offsets.DateOffset(days=1)
How do I tell python to check for the end of the month? MonthEnd is only an offset function.
Answers:
Here is a short function to accomplish this. It requires the dateutil module so that you can do relative date math.
import datetime
from dateutil.relativedelta import relativedelta
def lastyear_period_start(current_date):
last_year = current_date - relativedelta(months=11)
return datetime.date(last_year.year, last_year.month, 1)
It can be utilized like so:
dates = [
datetime.datetime(2010, 2, 27),
datetime.datetime(2011, 2, 27),
datetime.datetime(2012, 2, 27),
datetime.datetime(2013, 2, 27),
datetime.datetime(2014, 2, 27),
datetime.datetime(2010, 7, 27),
datetime.datetime(2011, 7, 27),
datetime.datetime(2012, 7, 27),
datetime.datetime(2013, 7, 27),
datetime.datetime(2014, 7, 27),
datetime.datetime(2015, 7, 14),
datetime.datetime(2015, 7, 31),
datetime.datetime(2011, 2, 28),
datetime.datetime(2012, 2, 29),
datetime.datetime(2013, 2, 28),
]
for d in dates:
print d, lastyear_period_start(d)
This prints that following
2010-02-27 00:00:00 2009-03-01
2011-02-27 00:00:00 2010-03-01
2012-02-27 00:00:00 2011-03-01
2013-02-27 00:00:00 2012-03-01
2014-02-27 00:00:00 2013-03-01
2010-07-27 00:00:00 2009-08-01
2011-07-27 00:00:00 2010-08-01
2012-07-27 00:00:00 2011-08-01
2013-07-27 00:00:00 2012-08-01
2014-07-27 00:00:00 2013-08-01
2015-07-14 00:00:00 2014-08-01
2015-07-31 00:00:00 2014-08-01
2011-02-28 00:00:00 2010-03-01
2012-02-29 00:00:00 2011-03-01
2013-02-28 00:00:00 2012-03-01
In the function we’re doing two simple steps
last_year = current_date - relativedelta(months=11)
First we find out what the date was 11 months ago, based on the date passed to the function
return datetime.date(last_year.year, last_year.month, 1)
Then we return the first day of that month.
In the output above you can see this accounts for leap years as well.
Alright, here’s what I did. Found the calendar module that BryanOakley suggested and made this loop. It checks the current day and checks if it is the same as the last day of the month, and chooses the range_min accordingly.
if datetime.datetime.now().day == calendar.monthrange(date.year, date.month)[1]:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)+ pd.tseries.offsets.DateOffset(days=1)
else:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)+ pd.tseries.offsets.MonthEnd(1) + pd.tseries.offsets.DateOffset(days=1)
I simply would use the monthrange method of calendar module to find last day number of the month:
def check_if_last_day_of_week(date):
import datetime
import calendar
# calendar.monthrange return a tuple (weekday of first day of the
# month, number
# of days in month)
last_day_of_month = calendar.monthrange(date.year, date.month)[1]
# here i check if date is last day of month
if date == datetime.date(date.year, date.month, last_day_of_month):
return True
return False
>>> date = datetime.date(2018, 12, 31)
>>> check_if_last_day_of_week(date)
True
We can avoid importing the calendar
module with a short function that only leverages datetime
.
If tomorrow’s month is not the same as today’s month, then that means today is the last day of the current month. We can check this programmatically with a short function such as
import datetime
def end_of_month(dt):
todays_month = dt.month
tomorrows_month = (dt + datetime.timedelta(days=1)).month
return tomorrows_month != todays_month
Now, for your specific use case:
now = datetime.datetime.now()
if end_of_month(now):
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)
else:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1) +pd.tseries.offsets.MonthEnd(1) + pd.tseries.offsets.DateOffset(days=1)
import datetime
def find_curr_month_end_date(curr_date):
if(curr_date.month != 12):
next_month_first_date= curr_date.replace(day=1).replace(month=curr_date.month+1)
else:
next_month_first_date= curr_date.replace(day=1).replace(month=1).replace(year=curr_date.year+1)
curr_month_end_date = next_month_first_date - datetime.timedelta(days=1)
return curr_month_end_date
curr_date = datetime.datetime.today()
# or curr_date = datetime.datetime.strptime("2020-12-16","%Y-%m-%d")
curr_month_end_date =
find_curr_month_end_date(curr_date)
I was using Pandas and I did not want to include another library, so I used this to check whether is the last day of the month and last day of the year:
import pandas as pd
my_date = '31-12-2021'
current_data = pd.to_datetime(my_date, format='%d-%m-%Y')
current_month = current_data.month
current_year = current_data.year
following_day = current_data + pd.DateOffset(1)
tomorrows_month = following_day.month
tomorrows_year = following_day.year
is_last_day_of_month = True if tomorrows_month != current_month else False
is_last_day_of_year = True if tomorrows_year != current_year else False
Here’s a pure python approach that also takes into account leap years for february:
# total days in every month during non leap years
M_DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def isleap(year):
"""Return True for leap years, False for non-leap years."""
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
def days_in_month(year, month):
"""Returns total number of days in a month accounting for leap years."""
return M_DAYS[month] + (month == 2 and isleap(year))
def is_monthend(ref_date):
"""Checks whether a date is also a monthend"""
return ref_date.day == days_in_month(ref_date.year, ref_date.month)
If the next day is a different month, it means it is the last day of a month.
def check_if_last_day_of_month(to_date):
delta = datetime.timedelta(days=1)
next_day = to_date + delta
if to_date.month != next_day.month:
return True
return False
I am writing code to take data from the last year. I want to round up the earlier date like so: If it is July 14 2015, I want data from August 1st 2014-July 14,2015
df = pd.read_csv('MyData.csv')
df['recvd_dttm'] = pd.to_datetime(df['recvd_dttm'])
range_max = datetime.datetime.now()
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)+ pd.tseries.offsets.MonthEnd(1) + pd.tseries.offsets.DateOffset(days=1)
if datetime.datetime.now() == is_month_end:
# take slice with final week of data
df = df[(df['recvd_dttm'] >= range_min) &
(df['recvd_dttm'] <= range_max)]
My problem is that when it is July 31, 2015, my code goes to the end of the next month, essentially cutting out an entire month.
I am trying to make a for loop to fix this problem.
If it is the end of the month:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)
else:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)+ pd.tseries.offsets.MonthEnd(1) + pd.tseries.offsets.DateOffset(days=1)
How do I tell python to check for the end of the month? MonthEnd is only an offset function.
Here is a short function to accomplish this. It requires the dateutil module so that you can do relative date math.
import datetime
from dateutil.relativedelta import relativedelta
def lastyear_period_start(current_date):
last_year = current_date - relativedelta(months=11)
return datetime.date(last_year.year, last_year.month, 1)
It can be utilized like so:
dates = [
datetime.datetime(2010, 2, 27),
datetime.datetime(2011, 2, 27),
datetime.datetime(2012, 2, 27),
datetime.datetime(2013, 2, 27),
datetime.datetime(2014, 2, 27),
datetime.datetime(2010, 7, 27),
datetime.datetime(2011, 7, 27),
datetime.datetime(2012, 7, 27),
datetime.datetime(2013, 7, 27),
datetime.datetime(2014, 7, 27),
datetime.datetime(2015, 7, 14),
datetime.datetime(2015, 7, 31),
datetime.datetime(2011, 2, 28),
datetime.datetime(2012, 2, 29),
datetime.datetime(2013, 2, 28),
]
for d in dates:
print d, lastyear_period_start(d)
This prints that following
2010-02-27 00:00:00 2009-03-01
2011-02-27 00:00:00 2010-03-01
2012-02-27 00:00:00 2011-03-01
2013-02-27 00:00:00 2012-03-01
2014-02-27 00:00:00 2013-03-01
2010-07-27 00:00:00 2009-08-01
2011-07-27 00:00:00 2010-08-01
2012-07-27 00:00:00 2011-08-01
2013-07-27 00:00:00 2012-08-01
2014-07-27 00:00:00 2013-08-01
2015-07-14 00:00:00 2014-08-01
2015-07-31 00:00:00 2014-08-01
2011-02-28 00:00:00 2010-03-01
2012-02-29 00:00:00 2011-03-01
2013-02-28 00:00:00 2012-03-01
In the function we’re doing two simple steps
last_year = current_date - relativedelta(months=11)
First we find out what the date was 11 months ago, based on the date passed to the function
return datetime.date(last_year.year, last_year.month, 1)
Then we return the first day of that month.
In the output above you can see this accounts for leap years as well.
Alright, here’s what I did. Found the calendar module that BryanOakley suggested and made this loop. It checks the current day and checks if it is the same as the last day of the month, and chooses the range_min accordingly.
if datetime.datetime.now().day == calendar.monthrange(date.year, date.month)[1]:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)+ pd.tseries.offsets.DateOffset(days=1)
else:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)+ pd.tseries.offsets.MonthEnd(1) + pd.tseries.offsets.DateOffset(days=1)
I simply would use the monthrange method of calendar module to find last day number of the month:
def check_if_last_day_of_week(date):
import datetime
import calendar
# calendar.monthrange return a tuple (weekday of first day of the
# month, number
# of days in month)
last_day_of_month = calendar.monthrange(date.year, date.month)[1]
# here i check if date is last day of month
if date == datetime.date(date.year, date.month, last_day_of_month):
return True
return False
>>> date = datetime.date(2018, 12, 31)
>>> check_if_last_day_of_week(date)
True
We can avoid importing the calendar
module with a short function that only leverages datetime
.
If tomorrow’s month is not the same as today’s month, then that means today is the last day of the current month. We can check this programmatically with a short function such as
import datetime
def end_of_month(dt):
todays_month = dt.month
tomorrows_month = (dt + datetime.timedelta(days=1)).month
return tomorrows_month != todays_month
Now, for your specific use case:
now = datetime.datetime.now()
if end_of_month(now):
range_min = range_max - pd.tseries.offsets.DateOffset(years=1)
else:
range_min = range_max - pd.tseries.offsets.DateOffset(years=1) +pd.tseries.offsets.MonthEnd(1) + pd.tseries.offsets.DateOffset(days=1)
import datetime
def find_curr_month_end_date(curr_date):
if(curr_date.month != 12):
next_month_first_date= curr_date.replace(day=1).replace(month=curr_date.month+1)
else:
next_month_first_date= curr_date.replace(day=1).replace(month=1).replace(year=curr_date.year+1)
curr_month_end_date = next_month_first_date - datetime.timedelta(days=1)
return curr_month_end_date
curr_date = datetime.datetime.today()
# or curr_date = datetime.datetime.strptime("2020-12-16","%Y-%m-%d")
curr_month_end_date =
find_curr_month_end_date(curr_date)
I was using Pandas and I did not want to include another library, so I used this to check whether is the last day of the month and last day of the year:
import pandas as pd
my_date = '31-12-2021'
current_data = pd.to_datetime(my_date, format='%d-%m-%Y')
current_month = current_data.month
current_year = current_data.year
following_day = current_data + pd.DateOffset(1)
tomorrows_month = following_day.month
tomorrows_year = following_day.year
is_last_day_of_month = True if tomorrows_month != current_month else False
is_last_day_of_year = True if tomorrows_year != current_year else False
Here’s a pure python approach that also takes into account leap years for february:
# total days in every month during non leap years
M_DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def isleap(year):
"""Return True for leap years, False for non-leap years."""
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
def days_in_month(year, month):
"""Returns total number of days in a month accounting for leap years."""
return M_DAYS[month] + (month == 2 and isleap(year))
def is_monthend(ref_date):
"""Checks whether a date is also a monthend"""
return ref_date.day == days_in_month(ref_date.year, ref_date.month)
If the next day is a different month, it means it is the last day of a month.
def check_if_last_day_of_month(to_date):
delta = datetime.timedelta(days=1)
next_day = to_date + delta
if to_date.month != next_day.month:
return True
return False