Learning how to calculate with date and time in Python
Lately I am doing a lot of Python again. Especially Django and I have to say I am starting to be productive with it. I was first fighting with the support of DB-views and other features MySQL 5 has finally bundled, but a couple fixes got me around. More about that in a later article.
While writing a couple of tests (btw still using testOOB) I needed to do some date and time calculation. I just wanted to update a timestamp in the DB and compare the delta. While I was thinking about how to do it, it popped to my mind, that I am probably thinking too complicated. So let’s try the obvious one.
>>> from datetime import datetime
>>> now = datetime.now()
>>> now - 1
Traceback (most recent call last):
File "< stdin>“, line 1, in ?
TypeError: unsupported operand type(s) for -: ‘datetime.datetime’ and ‘int’
Ok, I have to admit, that was just a bit too much I asked for. I was speculating that may be subtracting something from a date might result in some useful date. But I also knew that it will be impossible for the datetime class to know what to do with an integer that wants to be subtracted from it. Shall it be days, hours, years, etc.? Ok, so that one didn’t get us any further.
But there is always and easy way in Python, I know it. So let’s try something else:
>>> now - now
datetime.timedelta(0)
Aha, that looks interesting. And that means I can in fact subtract a date from a date. Here my difference is 0, but that was also not of interest now. More important: I learned about a class “datetime.timedelta”. Good to know.
Let’s try to play with it. Why play? As long as I am moving forward programming I feel much more confident about the results and that they stay in my leaking brain, than by reading a manual. Where I surely would find the answer to how timedelta works very quickly too.
So next step. How shall I use timedelta? Since I saw that subtracting dates from one another results in a timedelta object, I am sure that I can subtract a timedelta object from a date too.
>>> from datetime import timedelta
>>> t = timedelta(1)
>>> now - t
datetime.datetime(2006, 9, 17, 14, 18, 12, 377391)
>>> now
datetime.datetime(2006, 9, 18, 14, 18, 12, 377391)
Easy thing, it seems that timedelta(1) creates a timedelta object with the value of one day. (Now I am glimpsing in the Library Reference since help(timedelta) didn’t tell me what the constructor expects
that may should change).
The constructor contains all optional parameters, which is logical:
class timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]])
Alright that makes sense, the constructor can be used with named parameters of course which allows to create a timedelta of any kind. Some examples:
>>> now
datetime.datetime(2006, 9, 18, 14, 18, 12, 377391)
>>> now - timedelta(days=10) # Let’s go 10 days back (subtract!!!)
datetime.datetime(2006, 9, 8, 14, 18, 12, 377391)
>>> now - timedelta(days=10, hours=3) # 10 days and 3 hours back
datetime.datetime(2006, 9, 8, 11, 18, 12, 377391)
>>> now + timedelta(days=100, hours=3) # +100 days and 3 hours
datetime.datetime(2006, 12, 27, 17, 18, 12, 377391)
>>> now + timedelta(days=300, hours=3) # +300 days, should be next year.
datetime.datetime(2007, 7, 15, 17, 18, 12, 377391)
>>> now + timedelta(seconds=50) # 50 seconds more
datetime.datetime(2006, 9, 18, 14, 19, 2, 377391)
>>> now + timedelta(weeks=40) # 40 weeks more, should also be next year
datetime.datetime(2007, 6, 25, 14, 18, 12, 377391)
All that all looks pretty reasonable and simple, that is what I love about Python. And the cool thing, thanks to operator overloading we can do this in a very natural way, by simple adding or subtracting. That is a case where I clearly see the advantages of using operator overloading.
I have discussed this with a friend yesterday and he said “you can always use the timestamp in seconds for date calculations”, which is true. But when we go before 1970 that becomes interesting and also the conversion forth and back doesn’t add any value, this way is very aesthetic, better readable and less code in my eyes.
Rock on …
Markus said,
July 19, 2007 at 1:00 am
Thank you VERY much!
Helpful, easy and clear!
Regards,
Markus
stillatmycomputer said,
May 14, 2008 at 3:58 am
Great post
coolstar said,
July 18, 2008 at 5:35 pm
thanks of gr8 help
chad said,
August 12, 2008 at 3:53 pm
Great stuff, thanks for sharing, this keeps me from having to use mx.DateTime!
Joe said,
September 22, 2009 at 6:09 am
Thanks a lot for the concise, clear examples. The python docs have some examples but for timedelta they left a lot to be desired for me. Thanks again.
Joe
Brian Holdsworth said,
November 19, 2009 at 8:16 pm
Thanks for the post. This saved me some time by providing just what I needed to know in a concise manner and with plenty of examples.