faketime (libfaketime): LD_PRELOAD Your Way to Time Travel Without Touching the System Clock

2026-08-22

You need to test what your code does on Feb 29, 2028. Or verify that a certificate expiration path triggers cleanly. Or reproduce the bug that only happened at 03:14:07 UTC on January 19, 2038. The naive fix — sudo date -s ... — reaches out and yanks the wall clock for every process, breaks systemd timers, confuses your SSH session's Kerberos ticket, and if you're on a laptop, chrony will happily undo it 30 seconds later. There's a better way that's been sitting in Debian since 2007.

libfaketime is an LD_PRELOAD shim that intercepts time(), gettimeofday(), clock_gettime(), and friends — for one process and its children only. The system clock stays untouched. Cousin to eatmydata, same trick, different syscall family.

# Absolute time
faketime '2038-01-19 03:14:07' date
# → Tue Jan 19 03:14:07 UTC 2038

# Relative offsets — d/y/h/m/s
faketime '-3 years' openssl x509 -in cert.pem -noout -dates
faketime '+45 days' ./run_billing_job.sh

# ISO 8601 also works
faketime '2028-02-29T12:00:00' python -c 'import datetime; print(datetime.date.today())'

The real trick is the -f advanced format, which supports rate multipliers. Freeze time entirely, or make it march 10× faster to test a 24-hour cron in under three hours:

# Freeze — every call returns the same instant
faketime -f '2025-06-15 12:00:00 x0' bash
# now `sleep 5; date` returns the same timestamp

# Accelerate 60×: one wall-second = one faked-minute
faketime -f '@2025-01-01 00:00:00 x60' ./long_running_daemon

# Time drifts +1 second per real second, starting an hour ahead
faketime -f '+1h i1.0' ./scheduler_test.py

The killer application is testing TLS chains without waiting years. Every developer who's ever debugged a cert-expiry bug has faked the system clock and regretted it:

# What does our client do the day after this cert expires?
faketime "$(openssl x509 -in server.crt -noout -enddate | cut -d= -f2) + 1 day" \
  curl -v https://internal-api.example.com/

# Simulate an already-expired intermediate CA
faketime '2040-01-01' openssl s_client -connect example.com:443 -servername example.com

Point it at a whole test suite — pytest, go test, cargo test, whatever — and the tests see a world where it's already 2038:

FAKETIME='2038-01-19 03:14:08' pytest tests/test_timestamps.py
FAKETIME_NO_CACHE=1 FAKETIME='@1234567890' go test ./...

Environment variable form is usually what you want inside CI, because it propagates to fork()-ed children automatically. Combine with a per-process control file (FAKETIME_TIMESTAMP_FILE) and you can advance time from another shell while the process is running — perfect for testing token-refresh loops.

The fine print, learned the hard way:

The Debian package is faketime; on Fedora/RHEL it's libfaketime. Zero configuration, zero dependencies, works on anything glibc-based going back 15+ years.

Key Takeaway: When you need to test time-dependent code, don't touch the system clock — LD_PRELOAD a lie into one process with faketime, including rate multipliers for accelerated or frozen time.

All newsletters