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

J

John Yeung

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
 
J

John Yeung

[...] 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
 
A

Aahz

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. ;-)
 
J

John Machin

Roy Smith   said:
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.
 
D

Dennis Lee Bieber

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.
If I were to be strict (and I do tend to be that way when talking
algorithms), "add three months to Feb 28" means "add the duration equal
to 1/4 of a year to the date Feb 28"... And since, to me, a year is
365.25 days (I'm not quite strict enough to use 365.2522), that means
adding 91.3125 days... Yielding May 30 and a fraction (7.5 hours).

Yes -- when doing date calculations, I tend to withdraw to
astronomical Julian Date (which starts at Noon, BTW)
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
A

Aahz

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.
 
P

Peter Pearson

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.

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

Lorenzo

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.

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top