システム日付を偽装するdatefudgeコマンドを使う

はじめに

システムやアプリケーションのテストで、特定の日付での動作を確認したい場合がある。
datefudgeは、実際のシステム日付を変更せずに、特定のプロセスが認識する日付だけを偽装できるコマンドである。

時刻関連のテストやレガシーシステムの動作確認、期限切れ証明書のテストなどに便利である。

環境

Ubuntu 24.04 LTS
datefudge 1.26

datefudgeのインストール

sudo apt update
sudo apt install datefudge
ログ
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
  crack-common gyp libcares2 libgl1-amber-dri libglapi-mesa libjs-async libjs-events libjs-inherits
  libjs-is-typedarray libjs-prettify libjs-regenerate libjs-source-map libjs-sprintf-js
  libjs-typedarray-to-buffer libllvm17t64 liblttng-ust-common1t64 liblttng-ust-ctl5t64 liblttng-ust1t64
  libnotify-bin libqt5x11extras5 libre2-10 libssl-dev libuv1-dev libxcb-damage0 mesa-utils-bin node-abbrev
  node-ampproject-remapping node-ansi-regex node-ansi-styles node-aproba node-are-we-there-yet node-arrify
  node-async node-async-each node-auto-bind node-babel-plugin-add-module-exports node-babel7-runtime
  node-balanced-match node-base64-js node-binary-extensions node-brace-expansion node-busboy
  node-camelcase node-caniuse-lite node-chownr node-chrome-trace-event node-ci-info node-cjs-module-lexer
  node-cli-boxes node-cli-cursor node-clone node-collection-visit node-color-convert node-color-name
  node-colors node-commander node-commondir node-concat-stream node-console-control-strings
  node-convert-source-map node-core-js node-core-js-pure node-core-util-is node-data-uri-to-buffer
  node-decompress-response node-deep-is node-defaults node-define-property node-delegates node-depd
  node-diff node-electron-to-chromium node-encoding node-end-of-stream node-err-code node-error-ex
  node-es-module-lexer node-escape-string-regexp node-eslint-utils node-eslint-visitor-keys node-esquery
  node-estraverse node-esutils node-events node-fancy-log node-fast-deep-equal node-fast-levenshtein
  node-fetch node-find-up node-flatted node-foreground-child node-fs-readdir-recursive
  node-fs-write-stream-atomic node-fs.realpath node-function-bind node-get-caller-file node-get-stream
  node-get-value node-glob node-globals node-got node-graceful-fs node-growl node-has-flag
  node-has-unicode node-has-value node-has-values node-hosted-git-info node-iconv-lite node-ieee754
  node-iferr node-imurmurhash node-indent-string node-inflight node-inherits node-ini node-interpret
  node-ip node-ip-regex node-is-arrayish node-is-binary-path node-is-buffer node-is-descriptor
  node-is-extglob node-is-path-cwd node-is-plain-obj node-is-plain-object node-is-stream
  node-is-typedarray node-is-windows node-isarray node-isexe node-isobject node-js-tokens node-json-buffer
  node-json-parse-better-errors node-json-schema node-json-schema-traverse node-json-stable-stringify
  node-jsonify node-jsonparse node-kind-of node-levn node-loader-runner node-locate-path
  node-lodash-packages node-lowercase-keys node-lru-cache node-map-visit node-memfs node-merge-stream
  node-mimic-response node-minimatch node-minimist node-minipass node-mute-stream node-n3 node-negotiator
  node-npm-run-path node-object-inspect node-object-visit node-once node-optimist node-optionator
  node-osenv node-p-cancelable node-p-limit node-p-locate node-p-map node-pascalcase node-path-dirname
  node-path-exists node-path-is-absolute node-path-is-inside node-path-type node-pify node-pkg-dir
  node-postcss-value-parser node-prelude-ls node-process-nextick-args node-promise-inflight
  node-promise-retry node-promzard node-prr node-pump node-punycode node-quick-lru node-randombytes
  node-read node-readable-stream node-rechoir node-regenerator-runtime node-regenerator-transform
  node-regexpp node-regjsgen node-repeat-string node-require-directory node-require-from-string
  node-resolve node-resolve-cwd node-resolve-from node-restore-cursor node-resumer node-retry
  node-run-queue node-safe-buffer node-serialize-javascript node-set-blocking node-set-immediate-shim
  node-shebang-command node-shebang-regex node-shell-quote node-signal-exit node-slash node-slice-ansi
  node-source-list-map node-source-map node-spdx-correct node-spdx-exceptions node-spdx-expression-parse
  node-spdx-license-ids node-sprintf-js node-ssri node-stack-utils node-string-decoder node-strip-bom
  node-supports-color node-tapable node-terser node-text-table node-through node-time-stamp
  node-to-fast-properties node-tslib node-type-check node-typedarray node-typedarray-to-buffer node-undici
  node-unicode-canonical-property-names-ecmascript node-unicode-match-property-value-ecmascript
  node-unicode-property-aliases-ecmascript node-unset-value node-uri-js node-util-deprecate node-uuid
  node-v8flags node-validate-npm-package-license node-wcwidth.js node-webpack-sources node-wordwrap
  node-wrappy node-write-file-atomic node-xtend node-y18n node-yallist node-yaml nodejs-doc xbitmaps
Use 'sudo apt autoremove' to remove them.
The following NEW packages will be installed:
  datefudge
0 upgraded, 1 newly installed, 0 to remove and 31 not upgraded.
Need to get 8350 B of archives.
After this operation, 35.8 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble/universe amd64 datefudge amd64 1.26 [8350 B]
Fetched 8350 B in 1s (7893 B/s)
Selecting previously unselected package datefudge:amd64.
(Reading database ... 116728 files and directories currently installed.)
Preparing to unpack .../datefudge_1.26_amd64.deb ...
Unpacking datefudge:amd64 (1.26) ...
Setting up datefudge:amd64 (1.26) ...
Processing triggers for man-db (2.12.0-4build2) ...

インストール後、ヘルプを確認する。

datefudge --version
datefudge --version
/usr/bin/datefudge: Version 1.26

For usage information, use '/usr/bin/datefudge --help'.

datefudgeを使う

基本的な使い方

datefudgeの基本的な構文は以下の通り。

datefudge <偽装したい日付> <実行するコマンド> [コマンドの引数...]

例:

# dateコマンドを2020年1月1日として実行
datefudge "2020-01-01" date

# dateコマンドを2023年12月31日として実行  
datefudge "2023-12-31" date

# Pythonスクリプトを特定の日付で実行
datefudge "2022-06-15" python3 script.py

# 現在の日付と偽装した日付の比較
echo "現在の日付:" && date && echo "偽装した日付:" && datefudge "2023-12-31" date

この場合、指定したコマンド(datepython3など)とその子プロセスのみが偽装された日付を認識する。

日付の指定方法

日付は複数の形式で指定できる。

# YYYY-MM-DD形式(dateコマンドが偽装された日付で実行される)
datefudge "2020-01-01" date

# YYYY-MM-DD HH:MM:SS形式(dateコマンドが偽装された日付で実行される)
datefudge "2020-12-31 23:59:59" date

# MM/DD/YYYY形式も可能(dateコマンドが偽装された日付で実行される)
datefudge "12/31/2023" date

# 曜日と時刻を含む形式(dateコマンドが偽装された日付で実行される)
datefudge "Wed Jan 1 00:00:00 UTC 2020" date

上記の例では、datefudgeの後に指定した日付でdateコマンドが実行される。
重要: 偽装されるのはdatefudgeコマンドの引数として指定したプロセス(上記の例ではdateコマンド)とその子プロセスのみ。システム全体の日付は変更されない。

実際に使ってみる

現在の日付と偽装した日付の比較

実際にdatefudgeの効果を確認してみる。

echo "現在の日付:" && date && echo "偽装した日付:" && datefudge "2023-12-31" date
echo "現在の日付:" && date && echo "偽装した日付:" && datefudge "2023-12-31" date

現在の日付:
Sun Sep  7 01:14:16 JST 2025
偽装した日付:
Sun Dec 31 00:00:00 JST 2023

このように、datefudgeで指定したコマンドのみが偽装された日付で実行されていることがわかる。

特定の日付を指定して実行

datefudge "2020-01-01" date
Wed Jan  1 00:00:00 UTC 2020

実際のシステム日付は変更されていないことを確認。

date
Sat Sep  6 04:06:48 PM UTC 2025

複数コマンドの実行

シェルを起動して複数コマンドを実行する場合。

datefudge "2022-06-15" bash

この状態でシェル内で実行するコマンドは全て2022年6月15日として認識される。

date
 ~  datefudge "2022-06-15" bash

kbushi@kbushi:~$ date
Wed Jun 15 00:00:04 JST 2022

スクリプトファイルの実行

日付を偽装してスクリプトを実行する例。

# テスト用スクリプトの作成
cat << 'EOF' > test_date.sh
#!/bin/bash
echo "現在の日付: $(date)"
echo "エポック秒: $(date +%s)"
echo "年: $(date +%Y)"
echo "月: $(date +%m)"
echo "日: $(date +%d)"
EOF

chmod +x test_date.sh

通常実行。

./test_date.sh
現在の日付: Sun Sep  7 01:17:14 JST 2025
エポック秒: 1757175434
年: 2025
月: 09
日: 07

datefudgeで日付を偽装して実行。

datefudge "2000-01-01" ./test_date.sh
現在の日付: Sat Jan  1 00:00:00 JST 2000
エポック秒: 946652400
年: 2000
月: 01
日: 01

ファイルのタイムスタンプテスト

注意: datefudgeはファイルの変更時刻(modification times)は変更しない。ファイルのタイムスタンプは実際のシステム時刻で記録される。

# 過去の日付でファイルを作成してみる(実際には現在の日付で作成される)
datefudge "1999-12-31" touch old_file.txt

# 現在の日付でファイルを作成  
touch current_file.txt

# タイムスタンプを比較
ls -la *_file.txt
-rw-r--r-- 1 vscode vscode 0 Sep  6 16:18 old_file.txt
-rw-r--r-- 1 vscode vscode 0 Sep  6 16:18 current_file.txt

このように、どちらのファイルも同じ現在の日付で作成されている。datefudgeではtouchコマンドでファイルのタイムスタンプを偽装することはできない。

ファイルのタイムスタンプも偽装したい場合は、libfaketimeパッケージのfaketimeコマンドを使用する必要がある。

プログラムの期限テスト

期限切れや有効期限のテストに使用する例。

# Python スクリプトの例
cat << 'EOF' > check_expiry.py
#!/usr/bin/env python3
import datetime

expiry_date = datetime.date(2024, 12, 31)
today = datetime.date.today()

print(f"今日の日付: {today}")
print(f"期限日: {expiry_date}")

if today > expiry_date:
    print("期限切れです!")
    exit(1)
else:
    print("まだ有効です")
    exit(0)
EOF

chmod +x check_expiry.py

通常実行(2025年なので期限切れ)。

./check_expiry.py
今日の日付: 2025-09-07
期限日: 2024-12-31
期限切れです!

2024年として実行(有効)。

datefudge "2024-06-15" ./check_expiry.py
今日の日付: 2024-06-15
期限日: 2024-12-31
まだ有効です

注意点

1. システム全体には影響しない

datefudgeは指定したプロセスとその子プロセスにのみ影響する。システム全体の日付は変更されない。

2. 一部のアプリケーションでは効果がない

ハードウェアクロックを直接参照するアプリケーションや、特別な時刻取得方法を使用するアプリケーションでは効果がない場合がある。

3. ネットワーク関連の注意

NTPクライアントやネットワーク経由で時刻を取得するアプリケーションには影響しない。

4. ファイル変更時刻について

manページの「BUGS」セクションでは以下のように明記されている:

There is no attempt to make this change undetectable by the program. In particular, file modification times are not modified.

datefudgeはファイルの変更時刻(modification times)は変更しない。この機能が必要な場合は、libfaketimeパッケージのfaketimeコマンドを検討する。

5. 2038年問題の影響

manページでも2038年問題について言及されている:

On systems using 32-bit representation of time, datefudge is affected by the year 2038 problem, which might cause dates to be wrapped around, for instance:

32ビットシステムでは2038年問題の影響を受ける可能性がある。

# 例:2038年1月19日以降で予期しない動作が発生する可能性
TZ=UTC datefudge "2038-01-19 03:14:07" sh -c "sleep 1; date -R"
# 結果が1901年になってしまう場合がある(manページの例)
# Fri Dec 13 20:45:53 UTC 1901

6. –add-ld-preload オプションについて

manページには以下のオプションが記載されている

–add-ld-preload lib, -l lib
Prepend lib to LD_PRELOAD environment variable before executing given program. This option might be useful for example to inject sanitizer libraries (e.g. from Address Sanitizer) to the list of preloaded libraries before the internal datefudge’s library.

通常は自動的に処理されるが、特定の環境(Address Sanitizerなど)では明示的な指定が必要になることがある。

7. タイムゾーンについて

デフォルトではUTCで動作する。ローカルタイムゾーンを使用したい場合は環境変数TZを設定する。

TZ="Asia/Tokyo" datefudge "2024-01-01 09:00:00" date

関連コマンドとの比較

faketime との比較

libfaketimefaketimeコマンドも同様の機能を提供する。

# datefudge
datefudge "2020-01-01" date

# faketime  
faketime '2020-01-01' date
項目datefudgefaketime
軽量性シンプルで軽量より多機能だが重い
日付偽装基本的な日付偽装に特化より高機能な日付偽装
ファイル変更時刻変更しない偽装可能
制御オプション基本的なオプションのみ細かい制御オプションが豊富
適用場面シンプルな日付テストより複雑なテストシナリオ
パッケージdatefudgelibfaketime

manページでも、ファイル変更時刻について以下のように記載されている:

BUGS
There is no attempt to make this change undetectable by the program. In particular, file modification times are not modified.

(翻訳:このプログラムによる変更を検出不可能にする試みはない。特に、ファイルの変更時刻は変更されない。)

このため、ファイル変更時刻の偽装が必要な場合はfaketimeの使用が推奨されている。

参考

おわりに

datefudgeは、システム日付を変更せずに特定のプロセスの認識する日付だけを偽装できる便利なツールである。

時刻に依存するシステムのテストや、過去・未来の日付での動作確認に重宝する。
システム全体に影響を与えずにテストできるのが利点である。

バックアップスクリプトの動作確認や、期限切れ処理のテスト、年末年始の特別処理のテストなど、様々な場面で活用できるコマンドだと思った。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。