[Python-Dev] functions exposed by datetime

Tim Peters tim@zope.com
Wed, 15 Jan 2003 15:42:13 -0500


[Manuel Garcia, VP MIS]
> The more I read about "datetime", I am beginning to realize that like
> "mxDateTime", it is a needlessly awkward to use for people who want to
> cheaply turn a calendar date into a 32 bit integer, and back again. (an
> integer suitable for doing date arithmetic, of course)

I think you should try reading the modules' documentation next <wink>.

> 	for example:
> 		2/28/2004	38045
> 		2/29/2004	38046
> 		3/1/2004	38047
> 		3/2/2004	38048

>>> from datetime import date
>>> date(2004, 2, 29).toordinal()
731640
>>> date(2004, 3, 1).toordinal()
731641
>>> date.fromordinal(731640)
datetime.date(2004, 2, 29)
>>> date.fromordinal(731641)
datetime.date(2004, 3, 1)
>>>

> No matter how complete "datetime" turns out to be, you will have thousands
> of programmers that will have to code their own company's fiscal calendar
> anyway.  So it makes sense to have cheap access to date arithmetic logic.

You do.

> (I work for a manufacturing company, our fiscal months and years always
> begin on a Sunday, fiscal years are exactly 52 or 53 weeks long, and the
> length of a given year is determined as much by the tax code as by the
> positions of the earth and sun.)

Sure.

> And what is day zero?  Who cares?

In datetime, day 1 is 1/1/1, in the proleptic Gregorian calendar.  The
module docs say more about that.

> ...
> Besides date arithmetic, there are other reasons to make
> conversion between dates and integers very cheap.  32 bit integers
> obviously are easy to store, hash perfectly,

So do date objects.

> can be quickly put into bins with use of "bisect",

So can date objects directly.

> and they make calculations that loop over every day in a month or year a
> simple loop over a range(x,y).

There are many ways to do this, and I expect you're making life too
difficult if you keep converting to and from integers by hand.  Like

    x = some starting date in 2003
    aweek = datetime.timedelta(weeks=1)
    while x.year == 2003:
        do something with x
        x += aweek

This is cheap.

> The hashing is the biggest concern.  If I understand correctly, Guido said
> hash for datetime objects was not straightforward, because the same day
can
> have more than one representation.  I am constantly using a "date" for
part
> of a dictionary key.

A datetime.date object is basically a 4-byte string, and is no more
difficult or expensive to hash than the string "date".  A datetime object is
more complicated, *if* its tzinfo member isn't None.  Then hashing has to
take the time zone information into account, as different datetime objects
with non-None tzinfo members can represent the same time in UTC, and so
compare equal, and so must have the same hash codes.

> Sourceforge is gagging right now, so I cannot confirm what is in
> "datetime", but I never heard any mention of cheap conversion of dates
> into integers.

You can browse the module docs online at python.org too, via the
"development version" link on the doc page.

> My current fiscal calendar code uses mktime, localtime, int(round(x + (y -
> z) / 86400.0)), and prayer.  Currently the program is swamped by I/O, so
> this is good enough, and I can't justify installing "mxDateTime"
> on all the client machines.  But I wouldn't mind using a simple, cheap
> built-in.

Date ordinals are cheaper under mxDateTime, because it stores datetimes
internally as a pair

    (day ordinal as an integer, # of seconds into the day as a double)

datetime objects store year, month, day, hour, minute, second and
microsecond as distinct internal fields, for efficient field extraction and
exact (no floating point rounding surprises) datetime arithmetic.
Conversion to and from day ordinals requires non-trivial runtime conversion
code in datetime, but it runs at C speed and I expect you'll never notice
it.