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
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?"
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
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
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
--
Chris Green
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
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.
Whatever your requirement, chances are dateutil will be of help:
<http://labix.org/python-dateutil>
--
Ned Deily,
n...@acm.org
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
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.
> 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.
> 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 :-)
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...
> 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.
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
Yup, which calendar, what religion do you follow, where are you (and
if the answer is Sweden, which parish (according to legend)).
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)" :-)
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/
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!
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
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
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!
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.
--
Chris Green
You may want that; I'd rather just have less hassle. Nobody will ever
have problems with March 1.
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.
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
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