I'd like to add one month to a given date
import datetime
dt = datetime.datetime(year=2014, month=5, day=2)
so I should get
datetime.datetime(year=2014, month=6, day=2)
but with
dt = datetime.datetime(year=2015, month=1, day=31)
I should get
datetime.datetime(year=2015, month=3, day=1)
because there is no 2015-02-31 (and I want my result being round one day after)
Some months have 31 days, some other 30, some 29, some 28 !
so adding a datetime.timedelta
is probably not a good manner of doing (because we don't know the number of days to add)
I noticed that Pandas have an interesting concept of DateOffset
http://pandas.pydata.org/pandas-docs/stable/timeseries.html#dateoffset-objects
but I didn't find a Month
offset, just MonthBegin
or MonthEnd
I see also this post How do I calculate the date six months from the current date using the datetime Python 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)
so result was rounded one day before.
Is there a (clean) way to round day after ?
edit:
I gave an example with one month to add but I also want to be able to add for example : 2 years and 6 months (using a relativedelta(years=2, months=6)
)
Use the relativedelta class from the dateutil. relativedelta module to add months to a date in Python, e.g. result_1 = date_1 + relativedelta(months=+3) . The relativedelta class automatically handles months with different numbers of days.
You can use dateutil.relativedelta.relativedelta
and manually check the datetime.day
attribute, if the original day is greater than the new day, then add a day.
The function below accepts a datetime
object and relativedelta
object. Note that the code below only works for years and months, I don't believe it'll work if you use anything below that (days, hours, etc). You could easily modify this function to take years
and months
as arguments and then construct the 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
This seems to work. It is quite clean, but not beautiful:
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
It adds one month and tries to replace the day with the original day. If it succeeds, it is no special case. If it fails (ValueError), we have to add another month and go to its first day.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With