Add one month to the specified date (rounded day after) using Python

I would like to add one month to the specified date

import datetime dt = datetime.datetime(year=2014, month=5, day=2) 

so i have to get

 datetime.datetime(year=2014, month=6, day=2) 

but with

 dt = datetime.datetime(year=2015, month=1, day=31) 

I have to get

 datetime.datetime(year=2015, month=3, day=1) 

because no 2015-02-31 (and I want my result to be within one day after )

Some months have 31 days, some others 30, about 29, some 28!

so adding datetime.timedelta is probably not very good (because we don’t know the number of days to add)

I noticed that Pandas has an interesting concept DateOffset

http://pandas.pydata.org/pandas-docs/stable/timeseries.html#dateoffset-objects

but I did not find the offset Month , just MonthBegin or MonthEnd

I also see this post. How to calculate the date six months from the current date using the Python datetime module?

so i tried dateutil.relativedelta but

 from dateutil.relativedelta import relativedelta datetime.datetime(year=2015, month=1, day=31)+relativedelta(months=1) 

returns

 datetime.datetime(2015, 2, 28, 0, 0) 

therefore, the result is rounded up one day before .

Is there a (clean) way to round the day after ?

edit: I gave an example with the addition of one month, but I also want to add, for example: 2 years and 6 months (using relativedelta(years=2, months=6) )

+8
python pandas calendar timedelta python-dateutil
source share
3 answers

You can use dateutil.relativedelta.relativedelta and manually check datetime.day if the source day is more than a new day, then add a day.

The function below takes a datetime and relativedelta object. Please note that the code below only works for years and months, I don’t think it will work if you use anything below (days, hours, etc.). You can easily modify this function to take years and months as arguments, and then build relativedelta inside the function itself.

 from datetime import datetime from dateutil.relativedelta import relativedelta def add_time(d, rd): day = relativedelta(days=+1) out = d + rd if d.day > out.day: out = out + day return out # Check that it "rolls over" print(add_time(datetime(year=2015, month=1, day=29), relativedelta(years=+4, months=+1))) # 2019-03-01 00:00:00 print(add_time(datetime(year=2015, month=3, day=31), relativedelta(years=+0, months=+2))) # 2015-05-01 00:00:00 # Check that it handles "normal" scenarios print(add_time(datetime(year=2015, month=6, day=19), relativedelta(months=+1))) # 2015-07-19 00:00:00 print(add_time(datetime(year=2015, month=6, day=30), relativedelta(years=+2, months=+1))) # 2017-07-30 00:00:00 # Check across years print(add_time(datetime(year=2015, month=12, day=25), relativedelta(months=+1))) # 2016-01-25 00:00:00 # Check leap years print(add_time(datetime(year=2016, month=1, day=29), relativedelta(years=+4, months=+1))) # 2020-02-29 00:00:00 
+3
source share

It seems to work. This is pretty clean, but not pretty:

 def add_month(now): try: then = (now + relativedelta(months=1)).replace(day=now.day) except ValueError: then = (now + relativedelta(months=2)).replace(day=1) return then for now in [datetime(2015, 1, 20), datetime(2015, 1, 31), datetime(2015, 2, 28)]: print now, add_month(now) 

prints:

 2015-01-20 00:00:00 2015-02-20 00:00:00 2015-01-31 00:00:00 2015-03-01 00:00:00 2015-02-28 00:00:00 2015-03-28 00:00:00 

He adds one month and tries to replace the day with the original day. If it succeeds, this is not a special case. If it fails (ValueError), we must add another month and go to its first day.

+2
source share

Fast decision:

 import datetime import calendar dt = datetime.datetime(year=2014, month=5, day=2) d = calendar.monthrange(dt.year,dt.month+1)[1] print dt+datetime.timedelta(days=d+1) 

The output for the first entry (year=2014, month=5, day=2) :

 2014-06-02 00:00:00 

The output for the second entry (year=2015, month=1, day=31) :

 2015-03-01 00:00:00 
0
source share

All Articles