Leahs Gedanken

Lass uns ein Stück gemeinsam gehen

Not all seconds are the same.

Today at work, I investigated some problems with our firewall management software called Heimdal. After adding more instrumentation and finding another bug, I noticed that the number of active rules decreased much faster than they should.

If everything was correct, all lines should always match the violet line at the top of the graph above. After looking at the original values and further debugging, I was able to pin it down to the replay function. This function is needed to replay the firewall rules with the remaining block time after a router reboot. This is needed because address list entries with a timeout value are not reboot-safe on our Mikrotik hardware. To calculate the remaining time, I used this line of code:

remaining_seconds = ((address.block_timestamp+datetime.timedelta(seconds=address.block_duration))-datetime.datetime.now()).seconds

What I expected was to get the total of seconds left to re-add the rule with the correct timeout to the firewall. But you guessed it; that was not what I got. Instead, during debugging, I got this:

At first glance, everything looks good, but at the second, the last line seems odd. That’s because 83089 seconds are not nearly 19 days. Instead, 83089 seconds are exactly 23:04:49 hours. Sounds familiar? These are, indeed, the hours, minutes, and seconds in the second last line. So I looked up what timedelta.seconds actually does in the Python docs and was surprised by a big yellow warning box informing me that I’ve made a very common mistake.

So timedelta.seconds returns exactly what I got. The hours, minutes, and seconds of the timedelta I calculated. But this is still not what I want. To get what I was expecting my code would calculate in the first place, I need to use timedelta.total_seconds(). Totally counterintuitive, but this is only raising another question: “Why?”

After talking to a colleague, they explained to me that the timedelta object internally only holds days, seconds, and microseconds. Everything else is transformed into these three types, so this behavior is at least somewhat consistent, but still confusing. They also added some guesses as to why everything is broken down to these three types, but it is late and I have no motivation to dive into Python this deep this afternoon. Sorry.