Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to add months to a date (datetime object)?

10,308 views
Skip to first unread message

tin...@isbd.co.uk

unread,
Mar 15, 2009, 1:28:24 PM3/15/09
to
I have a date in the form of a datetime object and I want to add (for
example) three months to it. At the moment I can't see any very
obvious way of doing this. I need something like:-

myDate = datetime.date.today()
inc = datetime.timedelta(months=3)
myDate += inc

but, of course, timedelta doesn't know about months. I had a look at
the calendar object but that didn't seem to help much.

--
Chris Green

Roy Smith

unread,
Mar 15, 2009, 1:45:02 PM3/15/09
to
In article <49bd3ab8$0$510$bed6...@news.gradwell.net>, tin...@isbd.co.uk
wrote:

Well, before you can "add three months" to something, you need to explain
what that means.

What is Nov 29th plus 3 months?

What is Jan 31st plus 3 months?

Months are different lengths. Asking to "add 3 months" is kind of like
asking, "If I'm somewhere in the continental US (east of the Mississippi
River) and move three states to the west, how many miles have I moved?"

Chris Rebert

unread,
Mar 15, 2009, 1:46:53 PM3/15/09
to tin...@isbd.co.uk, pytho...@python.org
On Sun, Mar 15, 2009 at 10:28 AM, <tin...@isbd.co.uk> wrote:
> I have a date in the form of a datetime object and I want to add (for
> example) three months to it.  At the moment I can't see any very
> obvious way of doing this.  I need something like:-
>
>    myDate = datetime.date.today()
>    inc = datetime.timedelta(months=3)
>    myDate += inc
>
> but, of course, timedelta doesn't know about months.

Which makes some sense considering a month can range from 28-31 days,
which would make the delta oddly fuzzy.

Here's one approach:
myDate = datetime.date.today()
newYear = myDate.year
newMonth = myDate.month + 3
if newMonth > 12:
newYear += 1
newMonth -= 12
inThreeMonths = datetime.date(newYear, newMonth, myDate.day)
#add extra analogous logic if you have to deal with February or 31st days.

Cheers,
Chris

--
I have a blog:
http://blog.rebertia.com

Vlastimil Brom

unread,
Mar 15, 2009, 1:47:17 PM3/15/09
to tin...@isbd.co.uk, pytho...@python.org
2009/3/15 <tin...@isbd.co.uk>:
> --
> http://mail.python.org/mailman/listinfo/python-list
>

I guess, one can simply do this manually:

>>> td = datetime.date.today()
>>> td
datetime.date(2009, 3, 15)
>>> td_plus_3_months = datetime.date(td.year, td.month+3, td.day)
>>> td_plus_3_months
datetime.date(2009, 6, 15)


however, one have to check for non existing dates:
>>> datetime.date(td.year, td.month+10, td.day)
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: month must be in 1..12
>>>

hth
vbr

tin...@isbd.co.uk

unread,
Mar 15, 2009, 2:00:50 PM3/15/09
to

No, it's perfectly possible applying simple logic. My reminder
program manages it perfectly well. I have, for example, two sets of
three monthly reminders.

One starts on Jan 19th and repeats three monthly, that means Jan
19th, April 19th, July 19th and October 19th. Very simple.

The other is a little more difficult, it starts on December 31st
and repeats three monthly. So that one is on December 31st, March
31st, June 30th and September 30th.

The calendar program manages it perfectly well using what seems to me
fairly obvious logic, what I want is to be able to do the same in
Python.

I.e. in simple terms I want the "same day N months hence" and, if it
doesn't exist then the nearest possible.

--
Chris Green

tin...@isbd.co.uk

unread,
Mar 15, 2009, 2:02:20 PM3/15/09
to
I was just hoping there was some calendar object in Python which could
do all that for me (I need the handling of 31st and February etc.)

--
Chris Green

Andre Engels

unread,
Mar 15, 2009, 2:13:44 PM3/15/09
to tin...@isbd.co.uk, pytho...@python.org

Well, that's one way of defining it, but it does have some
consequences you have to watch out for. In particular, it means that
the following equalities do not necessarily hold:

Date + 2 months = Date + 1 month + 1 month
Date = Date + 1 month - 1 month

not to mention anything where you use days or weeks in combination
with months...

--
André Engels, andre...@gmail.com

Chris Rebert

unread,
Mar 15, 2009, 2:14:18 PM3/15/09
to tin...@isbd.co.uk, pytho...@python.org

But that's not what you said originally; you now fleshed out important
details. Your original question was simpler and more ambiguous.
The problem here is that there are multiple ways to handle the
ambiguous situations and there's no objective, obvious right choice.
Thus, though one must implement it by oneself, one gets exactly the
behavior one desires.
Besides your behavior, one could equally well argue that a 31st repeat
on months without a 31st should just be dropped, or that it should
carry over onto the 1st of the next month (ignoring the complications
of February). Which behavior one needs is completely
context-dependent.

Ned Deily

unread,
Mar 15, 2009, 2:21:23 PM3/15/09
to pytho...@python.org
In article <49bd42ac$0$512$bed6...@news.gradwell.net>,

tin...@isbd.co.uk wrote:
> I was just hoping there was some calendar object in Python which could
> do all that for me (I need the handling of 31st and February etc.)

Whatever your requirement, chances are dateutil will be of help:

<http://labix.org/python-dateutil>

--
Ned Deily,
n...@acm.org

Casey Webster

unread,
Mar 15, 2009, 3:10:43 PM3/15/09
to
On Mar 15, 2:00 pm, tinn...@isbd.co.uk wrote:
> No, it's perfectly possible applying simple logic.  My reminder
> program manages it perfectly well.  I have, for example, two sets of
> three monthly reminders.
>
>     One starts on Jan 19th and repeats three monthly, that means Jan
>     19th, April 19th, July 19th and October 19th.  Very simple.
>
>     The other is a little more difficult, it starts on December 31st
>     and repeats three monthly.  So that one is on December 31st, March
>     31st, June 30th and September 30th.
>
> The calendar program manages it perfectly well using what seems to me
> fairly obvious logic, what I want is to be able to do the same in
> Python.

The example you give does have fairly obvious logic. But how does it
handle Feb 28th, 2009 + 3 months? To me, there are two "obvious"
answers: May 28th, 2009 or May 31st, 2009. The question is intent; is
Feb 28th an arbitrary day of the month, or is it the last day of the
month, which for something like a monthly bill reminder is more likely?

John Yeung

unread,
Mar 15, 2009, 3:55:13 PM3/15/09
to
On Mar 15, 3:10 pm, Casey Webster <Casey...@gmail.com> wrote:
> The example you give does have fairly obvious logic. But how does it
> handle Feb 28th, 2009 + 3 months?  To me, there are two "obvious"
> answers: May 28th, 2009 or May 31st, 2009.  The question is intent; is
> Feb 28th an arbitrary day of the month, or is it the last day of the
> month, which for something like a monthly bill reminder is more likely?

In my experience, unless there is explicit verbiage that says "last
day of the month", the day of the month is always retained except
where it would result in an invalid date. (So May 28 in your
example.)

I sympathize with anyone who considers "lay person date math" ugly and
not always logical, in a mathematician's sense of logic. But the fact
of the matter is that LPDM is quite well established and not very
ambiguous at all.

John

Roy Smith

unread,
Mar 15, 2009, 4:21:13 PM3/15/09
to
In article <49bd4252$0$512$bed6...@news.gradwell.net>, tin...@isbd.co.uk
wrote:


> > Well, before you can "add three months" to something, you need to explain
> > what that means.
> [...]

> No, it's perfectly possible applying simple logic.

I didn't say it was not possible. I just said that a precursor to doing it
is understand what you mean by "add three months". There is no universal
definition for what that means.

Roy Smith

unread,
Mar 15, 2009, 4:27:01 PM3/15/09
to
In article <mailman.1915.1237140...@python.org>,
Chris Rebert <cl...@rebertia.com> wrote:

> Besides your behavior, one could equally well argue that a 31st repeat
> on months without a 31st should just be dropped, or that it should
> carry over onto the 1st of the next month (ignoring the complications
> of February). Which behavior one needs is completely
> context-dependent.

Indeed. For example, my wife started her current job on a Feb 29th. There
are significant financial events that happen on various anniversaries of
her employment (vesting of stock and retirement benefits). It really is
important that everybody know exactly what is meant by "10 years from Feb
29th, on a given year", and what it means in one context may not mean what
it means in another.

Roy Smith

unread,
Mar 15, 2009, 4:30:13 PM3/15/09
to
In article <mailman.1910.1237139...@python.org>,
Chris Rebert <cl...@rebertia.com> wrote:

> Which makes some sense considering a month can range from 28-31 days,
> which would make the delta oddly fuzzy.

BTW, what date is "One month after August 10, 1752"? Extra points if you
refuse the answer the question on the grounds that it's incompletely
specified :-)

Chris Rebert

unread,
Mar 15, 2009, 4:45:36 PM3/15/09
to Roy Smith, pytho...@python.org

Not that that date could even be represented by most programs since
it's before 1970. Talk about recentism! :-)
I've always wondered how historians using computers deal with that limitation...

Roy Smith

unread,
Mar 15, 2009, 5:44:47 PM3/15/09
to
In article <mailman.1924.1237149...@python.org>,
Chris Rebert <cl...@rebertia.com> wrote:

> Not that that date could even be represented by most programs since
> it's before 1970. Talk about recentism! :-)
> I've always wondered how historians using computers deal with that
> limitation...

The unix time format it well known for being extremely limited both in
terms of extent and precision. Julian Date
(http://en.wikipedia.org/wiki/Julian_date) is a commonly used time scale
for working with events far into the past or future.

CM

unread,
Mar 15, 2009, 5:47:19 PM3/15/09
to

As someone pointed out, dateutil to the rescue:

>>> import datetime
>>> from dateutil.relativedelta import *

>>> now = datetime.date.today()
>>> now
datetime.date(2009, 3, 15)

>>> now+relativedelta(months=+3)
datetime.date(2009, 6, 15)

Che

John Machin

unread,
Mar 15, 2009, 5:57:35 PM3/15/09
to
On Mar 16, 7:30 am, Roy Smith <r...@panix.com> wrote:
> In article <mailman.1910.1237139217.11746.python-l...@python.org>,

>  Chris Rebert <c...@rebertia.com> wrote:
>
> > Which makes some sense considering a month can range from 28-31 days,
> > which would make the delta oddly fuzzy.
>
> BTW, what date is "One month after August 10, 1752"?  Extra points if you
> refuse the answer the question on the grounds that it's incompletely
> specified :-)

Yup, which calendar, what religion do you follow, where are you (and
if the answer is Sweden, which parish (according to legend)).

John Machin

unread,
Mar 15, 2009, 6:25:42 PM3/15/09
to

A couple of issues here:

(1) The number of days in a month is not a constant, so "a
mathematician's sense of logic" is quite irrelevant.

(2) The various *different* LPDMs are quite well established and each
of them can be reduced to non-ambiguous rules provided that the
reducer is patient and persistent and avoids terms like "ugly",
"illogical", "ludicrous" ... early stages of the reduction process can
produce things like "31 January plus 1 month -> 3 March (2 March in a
leap year)" :-)

Steve Holden

unread,
Mar 15, 2009, 7:17:20 PM3/15/09
to pytho...@python.org
> --
> http://mail.python.org/mailman/listinfo/python-list
>
OK, suppose I sign a contract on Nov 30 that requires me to make
quarterly payments. When is my next payment due?

The use case doesn't seem that unreasonable to me.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/
Want to know? Come to PyCon - soon! http://us.pycon.org/

Chris Rebert

unread,
Mar 15, 2009, 7:26:12 PM3/15/09
to Steve Holden, pytho...@python.org
>> --
>> http://mail.python.org/mailman/listinfo/python-list
>>
> OK, suppose I sign a contract on Nov 30 that requires me to make
> quarterly payments. When is my next payment due?
>
> The use case doesn't seem that unreasonable to me.

Indeed, but the point is that there are likewise reasonable usecases
for the other behaviors too and one should refuse to guess in the face
of ambiguity; the std lib has, merely by default in this case, taken
this to the extreme of not implementing any of them directly.

Somewhat unrelated wish: if only dateutil were in the std lib... Alas!

John Yeung

unread,
Mar 15, 2009, 8:33:39 PM3/15/09
to
On Mar 15, 6:25 pm, John Machin <sjmac...@lexicon.net> wrote:
> A couple of issues here:
>
> (1) The number of days in a month is not a constant, so "a
> mathematician's sense of logic" is quite irrelevant.

It's relevant in the sense that some commenters on this thread seem to
want to apply some semblance of mathematical logic to the problem.
Also, I referred to *date* math as not always being mathematically
logical, not *month* math (which some might argue is inherently not
subject to mathematical logic; perhaps this is your position, I can't
quite tell if that's the intent of your statement).

> (2) The various *different* LPDMs are quite well established
> and each of them can be reduced to non-ambiguous rules provided
> that the reducer is patient and persistent and avoids terms
> like "ugly", "illogical", "ludicrous" ... early stages of the
> reduction process can produce things like "31 January plus 1
> month -> 3 March (2 March in a leap year)" :-)

I don't know if by "different LPDMs" you mean that "day math" is one
LPDM and "month math" is another, not quite compatible LPDM; or if you
mean there are several well-established meanings for the same verbal
expressions such as "add three months to Feb 28". If the former, then
I agree in principle, though with different terminology. If the
latter, I disagree, based on my experience.

I've done a lot of the reduction work you are talking about, and the
same verbal phrases tend to map to the same specific rules in the
end. Of course, that may not be everyone's experience, but it is
mine. It is also evidently the experience of dateutil's author and
the developers of all of the date routines and calendar programs I
have personally tried (which, granted, isn't all that many, but
includes extremely popular ones).

John

John Yeung

unread,
Mar 15, 2009, 9:01:53 PM3/15/09
to
On Mar 15, 7:26 pm, Chris Rebert <c...@rebertia.com> wrote:
> [...] the point is that there are likewise reasonable usecases

> for the other behaviors too and one should refuse to guess in
> the face of ambiguity; the std lib has, merely by default in
> this case, taken this to the extreme of not implementing any
> of them directly.
>
> Somewhat unrelated wish: if only dateutil were in the std
> lib... Alas!

dateutil makes a very clear choice about the behavior of month
arithmetic (namely, the one which the OP was after). Has it not
"guessed in the face of ambiguity"?

Personally, I don't think OP's original phrasing of the problem was
too ambiguous. I agree there are other reasonable interpretations,
but I disagree that his intention was unclear. His intention matches
what I believe to be the prevailing one; thus I don't find dateutil's
choice to be much of a guess.

John

Aahz

unread,
Mar 16, 2009, 12:08:41 AM3/16/09
to
In article <roy-C75465.1...@news.panix.com>,

Because I'm well-aware of such issues, I would have asked to make my
official start date March 1. ;-)
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

Adopt A Process -- stop killing all your children!

John Machin

unread,
Mar 16, 2009, 12:26:42 AM3/16/09
to
On Mar 16, 3:08 pm, a...@pythoncraft.com (Aahz) wrote:
> In article <roy-C75465.16270015032...@news.panix.com>,
> Roy Smith  <r...@panix.com> wrote:
>
> >In article <mailman.1915.1237140862.11746.python-l...@python.org>,

> > Chris Rebert <c...@rebertia.com> wrote:
>
> >> Besides your behavior, one could equally well argue that a 31st repeat
> >> on months without a 31st should just be dropped, or that it should
> >> carry over onto the 1st of the next month (ignoring the complications
> >> of February). Which behavior one needs is completely
> >> context-dependent.
>
> >Indeed.  For example, my wife started her current job on a Feb 29th.  There
> >are significant financial events that happen on various anniversaries of
> >her employment (vesting of stock and retirement benefits).  It really is
> >important that everybody know exactly what is meant by "10 years from Feb
> >29th, on a given year", and what it means in one context may not mean what
> >it means in another.
>
> Because I'm well-aware of such issues, I would have asked to make my
> official start date March 1.  ;-)

Which means that any goodies accruing after 4, 8, etc years are
granted on 1 March instead of the (obvious?) 29 February.

What you want is an agreement that the anniversary of commencement in
any year is the last day of February.


Message has been deleted

tin...@isbd.co.uk

unread,
Mar 16, 2009, 8:49:15 AM3/16/09
to
Yes, you are right, I think dateutil does what I need and thus I won't
have to reinvent the wheel. Thank you!

--
Chris Green

Aahz

unread,
Mar 16, 2009, 8:57:01 AM3/16/09
to
In article <b324a517-85ee-4260...@d36g2000prf.googlegroups.com>,
John Machin <sjma...@lexicon.net> wrote:

>On Mar 16, 3:08=A0pm, a...@pythoncraft.com (Aahz) wrote:
>> In article <roy-C75465.16270015032...@news.panix.com>,
>> Roy Smith =A0<r...@panix.com> wrote:
>>>>
>>>> Besides your behavior, one could equally well argue that a 31st repeat
>>>> on months without a 31st should just be dropped, or that it should
>>>> carry over onto the 1st of the next month (ignoring the complications
>>>> of February). Which behavior one needs is completely
>>>> context-dependent.
>>>
>>>Indeed. =A0For example, my wife started her current job on a Feb 29th. =
>=A0There

>>>are significant financial events that happen on various anniversaries of
>>>her employment (vesting of stock and retirement benefits). =A0It really =
>is
>>>important that everybody know exactly what is meant by "10 years from Fe=
>b
>>>29th, on a given year", and what it means in one context may not mean wh=

>at
>>>it means in another.
>>
>> Because I'm well-aware of such issues, I would have asked to make my
>> official start date March 1. =A0;-)

>
>Which means that any goodies accruing after 4, 8, etc years are
>granted on 1 March instead of the (obvious?) 29 February.
>
>What you want is an agreement that the anniversary of commencement in
>any year is the last day of February.

You may want that; I'd rather just have less hassle. Nobody will ever
have problems with March 1.

Peter Pearson

unread,
Mar 16, 2009, 10:59:29 AM3/16/09
to

Remember Frederic, in Pirates of Penzance, who was apprenticed
to a pirate until his twenty-first birthday, but was born on
Feb 29?

--
To email me, substitute nowhere->spamcop, invalid->net.

Lorenzo

unread,
Mar 16, 2009, 2:03:50 PM3/16/09
to
On Mar 15, 1:28 pm, tinn...@isbd.co.uk wrote:
> I have a date in the form of a datetime object and I want to add (for
> example) three months to it.  At the moment I can't see any very
> obvious way of doing this.  I need something like:-
>
>     myDate = datetime.date.today()
>     inc = datetime.timedelta(months=3)
>     myDate += inc
>
> but, of course, timedelta doesn't know about months. I had a look at
> the calendar object but that didn't seem to help much.
>
> --
> Chris Green

After seeing all this discussion, the best suggestion that comes to my
mind is:

Implement your own logic, and handle special cases as desired, using
calendar.monthrange as a reference to determine if the day really
exists on the new month. i.e.

from datetime import datetime
import calendar
months_to_add = 3
d = datetime.now()
if d.months + months_to_add > 12:
d.replace(year = d.year + (d.months + months_to_add)/12)
d.replace(month = (d.months + months_to_add)%12)
else:
d.replace(month = (d.months + months_to_add))
if d.day > calendar.monthrange(d.year,d.month)[1]:
# do some custom stuff i.e. force to last day of the month or skip
to the next month ....

just my .02

Scott David Daniels

unread,
Mar 16, 2009, 5:08:29 PM3/16/09
to
So, I see nobody has seen fit to make the obvious joke.
I will demonstrate my lack of restraint, by answering:

The way to add months to a date is to begin by
asking about your date's early childhood.

--Scott David Daniels
Scott....@Acm.Org

bajim...@gmail.com

unread,
Feb 2, 2017, 5:43:58 AM2/2/17
to
for start of month to the beginning of next month

from datetime import timedelta
from dateutil.relativedelta import relativedelta

end_date = start_date + relativedelta(months=delta_period) + timedelta(days=-delta_period)

Deborah Swanson

unread,
Feb 6, 2017, 3:23:22 AM2/6/17
to
bajim...@gmail.com wrote, on February 02, 2017 2:44 AM
Where do you define 'delta_period', and what is your question?

John Gordon

unread,
Feb 6, 2017, 4:54:40 PM2/6/17
to
There is no question; it is an answer in response to the original
post asking how to add months to a datetime object.

--
John Gordon A is for Amy, who fell down the stairs
gor...@panix.com B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"

MRAB

unread,
Feb 6, 2017, 5:17:42 PM2/6/17
to
On 2017-02-06 21:54, John Gordon wrote:
> In <mailman.23.14863693...@python.org> "Deborah Swanson" <pyt...@deborahswanson.net> writes:
>
>> bajim...@gmail.com wrote, on February 02, 2017 2:44 AM
>> >
>> > for start of month to the beginning of next month
>> >
>> > from datetime import timedelta
>> > from dateutil.relativedelta import relativedelta
>> >
>> > end_date = start_date + relativedelta(months=delta_period) +
>> > timedelta(days=-delta_period)
>
>> Where do you define 'delta_period', and what is your question?
>
> There is no question; it is an answer in response to the original
> post asking how to add months to a datetime object.
>
As far as I can find, the posts were from March 2009!

Deborah Swanson

unread,
Feb 6, 2017, 8:42:41 PM2/6/17
to
MRAB wrote,on February 06, 2017 2:17 PM
So that's why I couldn't find any previous posts with that title. And
it's hard to tell, sometimes newcomers fumble around and their first
successful post comes in with a Re: in front of the title.

John_...@f38.n261.z1

unread,
Feb 7, 2017, 1:47:50 PM2/7/17
to
From: John Gordon <gor...@panix.com>

In <mailman.23.14863693...@python.org> "Deborah Swanson"
<pyt...@deborahswanson.net> writes:

> bajim...@gmail.com wrote, on February 02, 2017 2:44 AM
> >
> > for start of month to the beginning of next month
> >
> > from datetime import timedelta
> > from dateutil.relativedelta import relativedelta
> >
> > end_date = start_date + relativedelta(months=delta_period) +
> > timedelta(days=-delta_period)

> Where do you define 'delta_period', and what is your question?

There is no question; it is an answer in response to the original post asking
how to add months to a datetime object.

John_...@f38.n261.z1

unread,
Feb 7, 2017, 2:49:16 PM2/7/17
to
From: John_...@f38.n261.z1

John_...@f38.n261.z1

unread,
Feb 8, 2017, 1:53:44 PM2/8/17
to
From: John_...@f38.n261.z1

John_...@f38.n261.z1

unread,
Feb 8, 2017, 2:51:18 PM2/8/17
to

John_...@f38.n261.z1

unread,
Feb 9, 2017, 1:53:20 PM2/9/17
to

John_...@f38.n261.z1

unread,
Feb 9, 2017, 2:49:39 PM2/9/17
to

abiodun....@gmail.com

unread,
Nov 22, 2017, 4:45:04 AM11/22/17
to
How about this...

from dateutil.relativedelta import relativedelta
myDate = datetime.date.today() + relativedelta(months=3)
0 new messages