(datetime — datetime).seconds

275 阅读1分钟
原文链接: medium.com

(datetime — datetime).seconds

Yet another WTF in a standard library

Go to the profile of George Shuklin
George ShuklinBlockedUnblockFollowFollowing

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 - event1datetime.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).seconds9902

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.