
Hey, I've recently been doing a lot of work with dates related to payment and statistics processing at work and have run into several annoyances with the built-in datetime, date, time, timedelta, etc classes, even when adding in relativedelta. They are awkward, non-intuitive and not at all Pythonic to me. Over the past year I've written up a library for making my life a bit easier and figured I would post some information here to see what others think, and to gauge whether or not such a library might be PEP-worthy. My original post about it was here: http://programmer-art.org/articles/programming/pythonic-date The github project page is here: http://github.com/danielgtaylor/paodate This is code that is and has been running in production environments for months but may still contain bugs. I have tried to include unit tests and ample documentation. I'd love to get some feedback and people's thoughts. I would also love to hear what others find is difficult or missing from the built-in date and time handling. Take care, -- Daniel G. Taylor http://programmer-art.org/

On Wed, Oct 13, 2010 at 04:04:28PM -0400, Daniel G. Taylor wrote:
http://programmer-art.org/articles/programming/pythonic-date
Have you ever tried mxDateTime. Do you consider it unpythonic? Oleg. -- Oleg Broytman http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN.

Daniel G. Taylor wrote:
mxDateTime implements most of these ideas: http://www.egenix.com/products/python/mxBase/mxDateTime/ It's been in production use for more than 13 years now and has proven to be very versatile in practice; YMMV, of course. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Oct 13 2010)
::: Try our new mxODBC.Connect Python Database Interface for free ! :::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/

On 10/13/2010 04:42 PM, M.-A. Lemburg wrote:
Hah, that is a very nice looking library. I wish I had looked into it before writing my own. Looks like it still doesn't allow write access to many properties in date or delta objects, but looks to have a lot of really useful stuff in it. I'll be taking a closer look shortly. Any idea why this hasn't made it into Python's standard library while being around for 13 years? Seems like it would be extremely useful in the standard distribution. Take care, -- Daniel G. Taylor http://programmer-art.org/

"Daniel G. Taylor" <dan@programmer-art.org> writes:
One barrier is that its license terms <URL:http://www.egenix.com/products/python/mxBase/eGenix.com-Public-License-1.1.0...> are incompatible with redistribution under the terms of the Python license. I'd love to see the mx code released under compatible license terms, but am not optimistic. -- \ “He that would make his own liberty secure must guard even his | `\ enemy from oppression.” —Thomas Paine | _o__) | Ben Finney

On Wed, Oct 13, 2010 at 4:04 PM, Daniel G. Taylor <dan@programmer-art.org> wrote:
There seems to be no shortage of blogosphere rants about how awkward python datetime module is, but once patches are posted on the tracker to improve it, nobody seems to be interested in reviewing them. I has been suggested that C implementation presented a high barrier to entry for people to get involved in datetime module development. This was one of the reasons I pushed for including a pure python equivalent in 3.2. Unfortunately, getting datetime.py into SVN tree was not enough to spark new interest in improving the module. Maybe this will change with datetime.py making it into a released version. ..
My original post about it was here:
http://programmer-art.org/articles/programming/pythonic-date
This post is severely lacking in detail, so I cannot tell how your library solves your announced problems, but most of them seem to be easy with datetime: * Make it easy to make a Date from anything - a timestamp, date, datetime, tuple, etc.
* Make it easy to turn a Date into anything datetime.timetuple() will convert datetime to a tuple. There is an open ticket to simplify datetime to timestamp conversion http://bugs.python.org/issue2736 but it is already easy enough:
(datetime.now() - datetime(1970,1,1)).total_seconds() 1286989863.82536
* Make it easy and pythonic to add/subtract one or more days, weeks, months, or years monthdelta addition was discussed at http://bugs.python.org/issue5434, but did not get enough interest. The rest seems to be easy enough with timedetla. * Make it easy to get a tuple of the start and end of the month Why would you want this? Start of the month is easy: just date(year, month, 1). End of the month is often unnecessary because it is more pythonic to work with semi-open ranges and use first of the next month instead.

On 10/13/2010 05:17 PM, Alexander Belopolsky wrote:
This at least sounds like some progress is being made, so that makes me happy. I'd be glad to work on stuff if I knew it has the potential to make a difference and be accepted upstream and if it doesn't require me rewriting every little thing in the module. I'm not really sure where to start as all I really want is a nice wrapper to make working with dates seem intuitive and friendly.
Yeah sorry it was mostly just a frustrated rant and then the start of my wrapper implementation.
Why does it not have this in the constructor? Where else in the standard lib does anything behave like this? My solution was to just dump whatever you want into the constructor and you get a Date object which can be converted to anything else via simple properties.
I'll be happy when this is fixed :-)
This is new in Python 2.7 it seems, before you had to calculate it by hand which was annoying to me. Now this seems okay.
And that means yet another module I have to import with various functions I have to use to manipulate an object rather than methods of the object itself. This doesn't seem Pythonic to me...
It's just for convenience really. For an example, I used it for querying a database for invoices in certain date ranges and for managing e.g. monthly recurring charges. It's just way more convenient and makes my code very easy to read where it counts - within the complex logic controlling when we charge credit cards. The less complex code there the better, because typos and bugs cost real money. Even if the tuples returned contained e.g. the first day of this and next month instead of the last day of the month it's still useful to have these properties that return the tuples (at least to me), as it saves some manual work each time. Take care, -- Daniel G. Taylor http://programmer-art.org/

On Wed, Oct 13, 2010 at 5:45 PM, Daniel G. Taylor <dan@programmer-art.org> wrote: ..
Because "explicit is better than implicit."
Where else in the standard lib does anything behave like this?
float.fromhex is one example. This said, if I was starting from scratch, I would make date/datetime constructors take a single positional argument that could be a string (interpreted as ISO timestamp), tuple (broken down components), or another date/datetime object. This would make date/datetime constructors more similar to those of numeric types. I would not add datetime(int) or datetime(float), however, because numeric timestamps are too ambiguous and not necessary for purely calendaric calculations.

On 13 October 2010 23:17, Alexander Belopolsky < alexander.belopolsky@gmail.com> wrote: * Make it easy to get a tuple of the start and end of the month
Except next month may well be in next year.. blah And I don't care about pythonic ranges if I have to push the values through a BETWEEN query in SQL. import calendar import datetime end = datetime.date(year, month, calendar.monthrange(year, month)[1])

On 2010-10-14, at 10:02 , Marco Mariani wrote:
There's also dateutil, which exposes some ideas of mx.DateTime on top of the built-in datetime, including relativedelta. As a result, you can get the last day of the current month by going backwards one day from the first day of next month:
datetime.now().date() + relativedelta(months=+1, day=+1, days=-1) datetime.date(2010, 10, 31)
Or (clearer order of operations):
datetime.now().date() + relativedelta(months=+1, day=+1) + relativedelta(days=-1) datetime.date(2010, 10, 31)
(note that in both cases the "+" sign is of course optional). Parameters without an `s` postfix are absolute (day=1 sets the day of the current datetime to 1, similar to using .replace), parameters with an `s` are offsets (`days=+1` takes tomorrow).

On 10/14/2010 08:06 AM, Masklinn wrote:
FWIW my library does the same sort of stuff using relativedelta internally, just sugar coats it heavily ;-) Take care, -- Daniel G. Taylor http://programmer-art.org/

On Wed, 2010-10-13 at 16:04 -0400, Daniel G. Taylor wrote:
Not convinced your library is very Pythonic. Why a tuple attribute instead of having date objects be iterable so you can do tuple(Date())? How does the fancy formats deal with locales? Is there support for ISO 8601? Should probably be the __str__. +1 on the general idea, though.

On 10/13/2010 06:16 PM, Dag Odenhall wrote:
Not convinced your library is very Pythonic. Why a tuple attribute instead of having date objects be iterable so you can do tuple(Date())?
How do you envision this working for days, weeks, months, years? E.g. getting the min/max Date objects for today, for next week, for this current month, etc. I'm very open to ideas here; I just implemented what made sense to me at the time.
How does the fancy formats deal with locales?
It internally uses datetime.strftime, so will behave however that behaves with regard to locales.
Is there support for ISO 8601? Should probably be the __str__.
Not built-in other than supporting a strftime method. This is a good idea and I will probably add it.
+1 on the general idea, though.
Thanks :-) Take care, -- Daniel G. Taylor http://programmer-art.org/

I'm glad to see there's interest in solving this (seems I'm not alone in seeing date/time support as the ugly stepchild of the Python standard library). For what it's worth, not too long ago I ended up writing a bunch of convenience functions to instantiate and convert between existing date/time representations (datetime objects, time tuples, timestamps, and string representations). The result is here, in case anyone's interested: http://www.cs.cmu.edu/~nschneid/docs/temporal.py Cheers, Nathan On Thu, Oct 14, 2010 at 2:54 PM, Daniel G. Taylor <dan@programmer-art.org> wrote:

On Wed, Oct 13, 2010 at 04:04:28PM -0400, Daniel G. Taylor wrote:
http://programmer-art.org/articles/programming/pythonic-date
Have you ever tried mxDateTime. Do you consider it unpythonic? Oleg. -- Oleg Broytman http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN.

Daniel G. Taylor wrote:
mxDateTime implements most of these ideas: http://www.egenix.com/products/python/mxBase/mxDateTime/ It's been in production use for more than 13 years now and has proven to be very versatile in practice; YMMV, of course. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Oct 13 2010)
::: Try our new mxODBC.Connect Python Database Interface for free ! :::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/

On 10/13/2010 04:42 PM, M.-A. Lemburg wrote:
Hah, that is a very nice looking library. I wish I had looked into it before writing my own. Looks like it still doesn't allow write access to many properties in date or delta objects, but looks to have a lot of really useful stuff in it. I'll be taking a closer look shortly. Any idea why this hasn't made it into Python's standard library while being around for 13 years? Seems like it would be extremely useful in the standard distribution. Take care, -- Daniel G. Taylor http://programmer-art.org/

"Daniel G. Taylor" <dan@programmer-art.org> writes:
One barrier is that its license terms <URL:http://www.egenix.com/products/python/mxBase/eGenix.com-Public-License-1.1.0...> are incompatible with redistribution under the terms of the Python license. I'd love to see the mx code released under compatible license terms, but am not optimistic. -- \ “He that would make his own liberty secure must guard even his | `\ enemy from oppression.” —Thomas Paine | _o__) | Ben Finney

On Wed, Oct 13, 2010 at 4:04 PM, Daniel G. Taylor <dan@programmer-art.org> wrote:
There seems to be no shortage of blogosphere rants about how awkward python datetime module is, but once patches are posted on the tracker to improve it, nobody seems to be interested in reviewing them. I has been suggested that C implementation presented a high barrier to entry for people to get involved in datetime module development. This was one of the reasons I pushed for including a pure python equivalent in 3.2. Unfortunately, getting datetime.py into SVN tree was not enough to spark new interest in improving the module. Maybe this will change with datetime.py making it into a released version. ..
My original post about it was here:
http://programmer-art.org/articles/programming/pythonic-date
This post is severely lacking in detail, so I cannot tell how your library solves your announced problems, but most of them seem to be easy with datetime: * Make it easy to make a Date from anything - a timestamp, date, datetime, tuple, etc.
* Make it easy to turn a Date into anything datetime.timetuple() will convert datetime to a tuple. There is an open ticket to simplify datetime to timestamp conversion http://bugs.python.org/issue2736 but it is already easy enough:
(datetime.now() - datetime(1970,1,1)).total_seconds() 1286989863.82536
* Make it easy and pythonic to add/subtract one or more days, weeks, months, or years monthdelta addition was discussed at http://bugs.python.org/issue5434, but did not get enough interest. The rest seems to be easy enough with timedetla. * Make it easy to get a tuple of the start and end of the month Why would you want this? Start of the month is easy: just date(year, month, 1). End of the month is often unnecessary because it is more pythonic to work with semi-open ranges and use first of the next month instead.

On 10/13/2010 05:17 PM, Alexander Belopolsky wrote:
This at least sounds like some progress is being made, so that makes me happy. I'd be glad to work on stuff if I knew it has the potential to make a difference and be accepted upstream and if it doesn't require me rewriting every little thing in the module. I'm not really sure where to start as all I really want is a nice wrapper to make working with dates seem intuitive and friendly.
Yeah sorry it was mostly just a frustrated rant and then the start of my wrapper implementation.
Why does it not have this in the constructor? Where else in the standard lib does anything behave like this? My solution was to just dump whatever you want into the constructor and you get a Date object which can be converted to anything else via simple properties.
I'll be happy when this is fixed :-)
This is new in Python 2.7 it seems, before you had to calculate it by hand which was annoying to me. Now this seems okay.
And that means yet another module I have to import with various functions I have to use to manipulate an object rather than methods of the object itself. This doesn't seem Pythonic to me...
It's just for convenience really. For an example, I used it for querying a database for invoices in certain date ranges and for managing e.g. monthly recurring charges. It's just way more convenient and makes my code very easy to read where it counts - within the complex logic controlling when we charge credit cards. The less complex code there the better, because typos and bugs cost real money. Even if the tuples returned contained e.g. the first day of this and next month instead of the last day of the month it's still useful to have these properties that return the tuples (at least to me), as it saves some manual work each time. Take care, -- Daniel G. Taylor http://programmer-art.org/

On Wed, Oct 13, 2010 at 5:45 PM, Daniel G. Taylor <dan@programmer-art.org> wrote: ..
Because "explicit is better than implicit."
Where else in the standard lib does anything behave like this?
float.fromhex is one example. This said, if I was starting from scratch, I would make date/datetime constructors take a single positional argument that could be a string (interpreted as ISO timestamp), tuple (broken down components), or another date/datetime object. This would make date/datetime constructors more similar to those of numeric types. I would not add datetime(int) or datetime(float), however, because numeric timestamps are too ambiguous and not necessary for purely calendaric calculations.

On 13 October 2010 23:17, Alexander Belopolsky < alexander.belopolsky@gmail.com> wrote: * Make it easy to get a tuple of the start and end of the month
Except next month may well be in next year.. blah And I don't care about pythonic ranges if I have to push the values through a BETWEEN query in SQL. import calendar import datetime end = datetime.date(year, month, calendar.monthrange(year, month)[1])

On 2010-10-14, at 10:02 , Marco Mariani wrote:
There's also dateutil, which exposes some ideas of mx.DateTime on top of the built-in datetime, including relativedelta. As a result, you can get the last day of the current month by going backwards one day from the first day of next month:
datetime.now().date() + relativedelta(months=+1, day=+1, days=-1) datetime.date(2010, 10, 31)
Or (clearer order of operations):
datetime.now().date() + relativedelta(months=+1, day=+1) + relativedelta(days=-1) datetime.date(2010, 10, 31)
(note that in both cases the "+" sign is of course optional). Parameters without an `s` postfix are absolute (day=1 sets the day of the current datetime to 1, similar to using .replace), parameters with an `s` are offsets (`days=+1` takes tomorrow).

On 10/14/2010 08:06 AM, Masklinn wrote:
FWIW my library does the same sort of stuff using relativedelta internally, just sugar coats it heavily ;-) Take care, -- Daniel G. Taylor http://programmer-art.org/

On Wed, 2010-10-13 at 16:04 -0400, Daniel G. Taylor wrote:
Not convinced your library is very Pythonic. Why a tuple attribute instead of having date objects be iterable so you can do tuple(Date())? How does the fancy formats deal with locales? Is there support for ISO 8601? Should probably be the __str__. +1 on the general idea, though.

On 10/13/2010 06:16 PM, Dag Odenhall wrote:
Not convinced your library is very Pythonic. Why a tuple attribute instead of having date objects be iterable so you can do tuple(Date())?
How do you envision this working for days, weeks, months, years? E.g. getting the min/max Date objects for today, for next week, for this current month, etc. I'm very open to ideas here; I just implemented what made sense to me at the time.
How does the fancy formats deal with locales?
It internally uses datetime.strftime, so will behave however that behaves with regard to locales.
Is there support for ISO 8601? Should probably be the __str__.
Not built-in other than supporting a strftime method. This is a good idea and I will probably add it.
+1 on the general idea, though.
Thanks :-) Take care, -- Daniel G. Taylor http://programmer-art.org/

I'm glad to see there's interest in solving this (seems I'm not alone in seeing date/time support as the ugly stepchild of the Python standard library). For what it's worth, not too long ago I ended up writing a bunch of convenience functions to instantiate and convert between existing date/time representations (datetime objects, time tuples, timestamps, and string representations). The result is here, in case anyone's interested: http://www.cs.cmu.edu/~nschneid/docs/temporal.py Cheers, Nathan On Thu, Oct 14, 2010 at 2:54 PM, Daniel G. Taylor <dan@programmer-art.org> wrote:
participants (10)
-
Alexander Belopolsky
-
Ben Finney
-
Dag Odenhall
-
Daniel G. Taylor
-
Daniel G. Taylor
-
M.-A. Lemburg
-
Marco Mariani
-
Masklinn
-
Nathan Schneider
-
Oleg Broytman