(datetime — datetime).seconds

Yet another WTF in a standard library

George Shuklin
Dec 24, 2018 · 2 min read

Today I got yet another story to tell about pitfalls in the Python standard library. Most of the Python library is well-written and is obvious to use. That creates a false sense of security. Reading the docs is essential, and today I have a story of big WTF for those, who do not read them. Count me in…

datetime

datetime is a descent module for handling objects with date and time. Everything related to time is complicated, because we have days, years, hours, summer time, timezones, leap seconds, leap years, leap weeks (…nah, I’ve invented that …I hope). Anyway, datetime gives a sane interface to handle some of that complexity. One of it’s nice features is a timedelta type, which is a return type for subtraction between two datetype objects. It says how much time is between two events. It even have a human-readable form for it:

>>> event1 = datetime.datetime(2018, 12, 4, 15, 9, 58, 1)
>>> event2 = datetime.datetime(2018, 12, 19, 17, 55, 0, 2)
>>> event2 - event1
datetime.timedelta(15, 9902, 1)
>>> str(event2 - event1)
'15 days, 2:45:02.000001'

What a nice library!

Pitfall ahead

I used it in my code to calculate number of seconds between to events. I made dir() on timedelta object and found this:

['__abs__',... 'days', 'max', 'microseconds', 'min', 'resolution', 'seconds'...

Good! timedelta.seconds is the answer. I had had a suspicion that it could be ‘number of seconds which is less then a minute (so, days=15, hours=2, minutes=45 seconds=2 for example from above). But it was a pretty big number, so I was wrong:

>>> (event2 - event1).seconds
9902

Excellent, it’s a number of seconds, I thought.

… Only after few months in production and after hour of debugging of some bizarre inconsistency in my script, I found that….

(yes, READ THE DOCS!)

 |  Data descriptors defined here:
| days
| Number of days.
|
| microseconds
| Number of microseconds (>= 0 and less than 1 second).
|
| seconds
| Number of seconds (>= 0 and less than 1 day).

The variable seconds have number of seconds less than day. The proper function to call (for my purposes is timedelta.total_seconds()).

So, timedelta.seconds is timedelta.total_seconds() % 86400

Good luck with debugging this.

Was I wrong? Yes. Have I made a mistake? Yes.

Do I feel WTFed? Yes, beyond recognition.

Python Pandemonium

A place to read and write about all things Python. If you want to become a writer for this publication then let me know.

George Shuklin

Written by

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux.

Python Pandemonium

A place to read and write about all things Python. If you want to become a writer for this publication then let me know.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade