Sometimes, on a lazy weekend afternoon, I use apt-get to pull down the
source of something and start grepping it for things that are bound to
be interesting. This is one of those afternoons, and I found something
silly. While looking for uses of time_t in bash, I found a variable
called “time_since_start”. Uh oh.
bash supports a dynamic variable called “SECONDS” (bet you didn’t know
that – I didn’t), and it’s documented as “the number of seconds
since shell invocation”. I’m sorry to say, that’s not quite true. You
can totally make it go negative since it’s based on wall time.
Just set the system clock back.
root@rpi4b:/tmp# systemctl stop chrony root@rpi4b:/tmp# echo $SECONDS 11 root@rpi4b:/tmp# date -s "2023-01-01 00:00:00Z" Sat 31 Dec 2022 04:00:00 PM PST root@rpi4b:/tmp# echo $SECONDS -2500987
That’s an extreme demonstration, but backwards-going wall time happens
every time we have a leap second. Granted, we’re in a long dry spell
at the moment, but it’ll probably happen again in our lifetimes. The
difference there is just one second, but it could break something if
someone relies on that value in a shell script.
Or, how about if the machine comes up with a really bad time for some
reason (did your hardware people
on the BOM and leave off the 25 cent real-time clock on the brand new
multi-thousand-dollar server?), the shell gets going, and later chrony
(or whatever) fixes it? Same deal, only then it might not be a second.
It might be much more.
In the case where the machine comes up with a past date and then jumps
forward, SECONDS on a still-running shell from before it’s fixed will be
far bigger than it should be. I’m pretty sure every Raspberry Pi
thinks it’s time=0 for a few moments when it first comes up because
there’s no RTC on the board. Run “last reboot” on one to see what I
I should also mention that bash does other similar things to (attempt
to) see how much time has passed. Have you ever noticed that it’ll
sometimes say “you have new mail”, for those rare people who actually
use old-school mail delivery? It only checks when enough time has
elapsed. I imagine a “negative duration” would mean no more checks.
The lesson here is that wall time is not to be used to measure
durations. Any time you see someone subtracting wall times (i.e.,
anything from time() or gettimeofday()), worry. Measure durations with
a monotonic clock if your device has one. The actual values are a
black box, but you can subtract one from the other and arrive at a
count of how many of their units have elapsed… ish.
Be sure to pay attention to which monotonic clock you use if you have a
choice and there’s any possibility the machine can go to sleep.
“Monotonic time I have been running” and “monotonic time since I was
booted” are two different things on such devices.
Here’s today’s bonus “smash head here” moment. From the man pages for
clock_gettime on a typical Linux box:
CLOCK_MONOTONIC: “This clock does not count time that the system is
Here’s the same bit on a current (Ventura) Mac:
CLOCK_MONOTONIC: “…and will continue to increment while the system
Ah yes, portability. The cause of, and solution to, all of life’s