Back to the future. Travel in time on your shell

When we write code, we often have it do something based on the current time. Some of my cronjobs suddenly showed a strange behavior in February. I could have prevented this with proper testing.

It was sometime in summer when I wrote those scripts that used the ISO week number I got with date +%V. Even though I tested my scripts with different time settings I ran into errors in week 8. It turned out that date +%V spits out the week number always with two digits and a prefixed 0 denotes an octal representation. 07 (octal) worked fine as it is equal to 7 (decimal) but 08 does not exist.

To run tests with different time settings we can use a simple program called faketime. Lets write some test code then (I copied the date loop from https://gist.github.com/chluehr/2502805)

#!/bin/bash

now=`date +"%Y-%m-%d" -d "01/01/2021"`
end=`date +"%Y-%m-%d" -d "12/31/2021"`

while [ "$now" != "$end" ] ; 
do 
        RESULT="OK"
        now=`date +"%Y-%m-%d" -d "$now + 1 day"`; 
        let test="$(faketime "${now}" date +%V) * 1" || RESULT="FAILED"
        echo "${now}: ${RESULT}"
done

You will see what happens if you run it.

My fix for this bug was to strip the leading 0 with

date +%-V

If you want to use faketime in your tests just be aware that it only works with dynamically linked binaries. It overrides clock_gettime that is normally called from libc. That means it will not work with statically linked binaries like Terraform for instance. If you work with a recent Kernel version you may want to use a time namespace for your test.

“Why do programmers always mix up Halloween and Christmas? Because Oct 31 = Dec 25.”

Contact