Mocking the system time

Testing your shell scripts can be complicated enough already but when you start to incorporate time based test scenarios you can quickly find yourself in the land of fragile tests and intermittent failures. By adding a small command line utility, called faketime, to your toolbox you can make your chronology related tests more reliable and reproducible.

To start we’ll install faketime. This focused little binary allows you to explicitly set the system time for which ever command you pass to it. On Fedora systems the install is as simple as:

sudo dnf install libfaketime

First we’ll run a normal date command to ensure everything is as we expect.

$ date
Sat 30 May 13:27:16 BST 2020

If we want to run our commands with a specific, and different date, we invoke faketime when we run them.

faketime '2008-12-24 08:15:42' date
Wed 24 Dec 08:15:42 GMT 2008

This allows you to test edge cases, such as behaviour on a leap day, or start your sequence of tests from a known good point. When testing systems that have longer waits between parts of their functionality you can run the commands with explicit times and ensure you handle each case.

# create the batch with a known good time
faketime '2008-10-24 08:15:42' write-batch.py

# test the handling of expired records by
# setting the time forward immediately
faketime '2008-12-24 08:15:42' process-batch.py --expiry 31
WARNING: Monthly data is out of stale. Older than 31 days

If you’re writing in a higher level language than shell there are sometimes more specific testing libraries to support this kind of functionality, such as Timecop in ruby. faketime can still be handy when you’re working with a language that lacks such niceties or are running in a constrained environment. The following example shows the time being explicitly set for an entire language runtime but still progress forward within the process.

faketime '2008-12-24 08:15:42' ruby -e 'puts Time.new ; sleep 5 ; puts Time.new'
2008-12-24 08:15:42 +0000
2008-12-24 08:15:47 +0000

And for old times sake here it is faking the time for a perl interpreter.

faketime '2008-12-24 08:15:42' perl -e 'print localtime . "\n"'
Wed Dec 24 08:15:42 2008

faketime is a very niche tool that provides flexibility in a narrow set of use cases. You won’t need it often but when you do it’s much easier to install it than try to kludge in your own implementation.