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) |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Why don't you provide your example of dates.
If your dates were 2020-04-01 to 2020-05-03, you would have 1 month (2020-04-01 to midnight 2020-04-30) plus then 3 of the 31 days of may, or 3/31 or 0.096 (or 0.10) of the month of may. That is the portion of the month of May that is included in your calculation.
The other way to view the part of the month is to think about it this way: the month of May has 31 days. So 1 day in the month of may is 1/31. Three days, is therefore 1/31 * 3, or 3/31.
Andrew