Last active
June 4, 2020 04:36
-
-
Save andrewyager/6b9284a4f1cdb1779b10 to your computer and use it in GitHub Desktop.
Calculate the fractional months between two dates, inclusively.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from datetime import datetime, date | |
import calendar | |
def monthdiff(start_period, end_period, decimal_places = 2): | |
if start_period > end_period: | |
raise Exception('Start is after end') | |
if start_period.year == end_period.year and start_period.month == end_period.month: | |
days_in_month = calendar.monthrange(start_period.year, start_period.month)[1] | |
days_to_charge = end_period.day - start_period.day+1 | |
diff = round(float(days_to_charge)/float(days_in_month), decimal_places) | |
return diff | |
months = 0 | |
# we have a start date within one month and not at the start, and an end date that is not | |
# in the same month as the start date | |
if start_period.day > 1: | |
last_day_in_start_month = calendar.monthrange(start_period.year, start_period.month)[1] | |
days_to_charge = last_day_in_start_month - start_period.day +1 | |
months = months + round(float(days_to_charge)/float(last_day_in_start_month), decimal_places) | |
start_period = datetime(start_period.year, start_period.month+1, 1) | |
last_day_in_last_month = calendar.monthrange(end_period.year, end_period.month)[1] | |
if end_period.day != last_day_in_last_month: | |
# we have less days in the last month | |
months = months + round(float(end_period.day) / float(last_day_in_last_month), decimal_places) | |
last_day_in_previous_month = calendar.monthrange(end_period.year, end_period.month - 1)[1] | |
end_period = datetime(end_period.year, end_period.month - 1, last_day_in_previous_month) | |
#whatever happens, we now have a period of whole months to calculate the difference between | |
if start_period != end_period: | |
months = months + (end_period.year - start_period.year) * 12 + (end_period.month - start_period.month) + 1 | |
# just counter for any final decimal place manipulation | |
diff = round(months, decimal_places) | |
return diff | |
assert monthdiff(datetime(2015,1,1), datetime(2015,1,31)) == 1 | |
assert monthdiff(datetime(2015,1,1), datetime(2015,02,01)) == 1.04 | |
assert monthdiff(datetime(2014,1,1), datetime(2014,12,31)) == 12 | |
assert monthdiff(datetime(2014,7,1), datetime(2015,06,30)) == 12 | |
assert monthdiff(datetime(2015,1,10), datetime(2015,01,20)) == 0.35 | |
assert monthdiff(datetime(2015,1,10), datetime(2015,02,20)) == 0.71 + 0.71 | |
assert monthdiff(datetime(2015,1,31), datetime(2015,02,01)) == round(1.0/31.0,2) + round(1.0/28.0,2) | |
assert monthdiff(datetime(2013,1,31), datetime(2015,02,01)) == 12*2 + round(1.0/31.0,2) + round(1.0/28.0,2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wanna use this to calculate the number of months between each month of the dataset and the current months.
Example 👍
today = date.today()
df_req1["ancienté_par_rapport_year"]=today.year-df_req1["year"]
if I have "2006-06-01" and today I know it's 14 years
I want the same thing for months and days