Datetime utility functions

Paul Moore paul.moore at
Mon Sep 15 21:44:08 CEST 2003

"John Roth" <newsgroups at> writes:

> "Paul Moore" <paul.moore at> wrote in message
> news:182bcf76.0309150707.3a8c0482 at

>> 1. Get the last day of the month contatining a given date(time). I
>> really was surprised to find this one missing, as it seems to me that
>> the datetime module must know what the last day for each month is, so
>> exposing it wouldn't have been hard.
> I'm kind of surprised to see that it's missing, too.

The best solution I could find was

def month_end(dt):
    # Get the next month
    y, m = dt.year, dt.month
    if m == 12:
        y += 1
        m = 1
        m += 1

    # Use replace to cater for both datetime and date types. This
    # leaves the time component of a datetime unchanged - it's
    # arguable whether this is the right thing.

    return dt.replace(year=y, month=m, day=1) - datetime.timedelta(days=1)

It's not hard - but it's mildly tricky (I made a few false starts and
some silly off-by-one errors) and I'd much rather grab it from a
library than make the same mistakes next time I need it.

>> 2. Add a number of months to a date. This is messy, as there are
>> options (what is one month after 31st Jan). The trouble is that the
>> calculation, while simple, is tricky to get right (month is 1-based,
>> so off-by-1 errors are easy to make, and divmod isn't as useful as
>> you'd first think).
> That's application dependent.

True. But for "naive" use, a simple definition does. This is in line
with the datetime module's philosophy of not trying to cater for
"advanced" uses, but to provide something useful for straightforward
use. In this particular case, I'd argue that the obvious definition
(same day number N months on) where applicable, plus a well-documented
"reasonable" answer for the edge cases (eg, Jan 31 plus 1 month) is
useful. In practice, I suspect that 99% of cases involve adding a
number of months to either the first or the last of a month.

> If a bond, for example, has interest payable on the 30th of the
> month, you probably want the 30th, except in February you want the
> last day of the month. However, the contract may specify something
> else. And in no case do you want the date to suddenly change to the
> 28th because you went through February.

But that's not so much a case of adding a month, as a more complex
concept, a "repeating date". Nevertheless, I take your point.

>> In the absence of anything else, I'll probably write a "date
>> utilities" module for myself at some point. But I'd hate to be
>> reinventing the wheel.
> There's a very well regarded date module out there in the
> Vaults of Parnassus. The name escapes me at the moment,
> but a bit of spelunking through the Vaults will turn up several
> date routines that may do what you want.

I guess you're thinking of mxDateTime. I'm aware of this, and agree
that it's pretty comprehensive. I don't really know why I prefer not
to use it - partly it's just a case of reducing dependencies, also
there are already so many date types in my code (COM, cx_Oracle,
datetime) that I am reluctant to add another - there is already far
too much code devoted to converting representations...

Thanks for the comments,
This signature intentionally left blank

More information about the Python-list mailing list