Linuxでファイルの最終変更日時を表示する方法とその応用の実務上の結論は「更新日時はstatの%y、機械比較は%Yを使い、mtime・ctime・birthtimeの意味を分けます。timezone、時刻精度、clock skewも記録します。」です。比較の基準はmtimeのepoch秒で、表示用日時はUTC変換した派生値です。inodeとclock状態を含め、未来時刻やsub-second精度の差を文字列比較だけで判断しません。
mtime・ctime・birth timeの役割
更新日時として通常確認するのはfile dataが最後に変わったmtimeです。ownerやmodeなどmetadataの変更で動くctime、filesystemが提供する場合のbirth timeとは意味が異なります。copy、archive展開、rsyncなどはmtimeを保持できるため、mtimeが古いことはそのhostへ古くから存在する証明にはなりません。clock skewとtimezoneも別に評価します。
stat –format=’%n %y’は人向け、%Yは比較用epoch秒です。複数fileを日付条件で抽出するfind -newermtでは基準日時のtimezone解釈を明記し、厳密な機械比較は%Yを整数として扱います。symbolic link自体を調べる場合と参照先を調べる場合を分け、directoryのmtimeは直下entryの作成・削除で変わることにも注意します。
mtime比較で揃えるclock・precision・対象inode
- mtimeを必要とする目的を定義する
- 対象filesystemの時刻精度を確認する
- UTCかlocal表示かを決める
- metadata変更とdata変更を区別する
deployでpathの中身が別inodeへ置換される場合、path名だけの前後比較は採用しません。device・inodeを保存し、host clockが未来を指す時は停止して、時刻同期の復旧後に同じsnapshotから採取します。
stat %yと%YをUTC基準へ結び付ける
mtimeを表示
stat --format='%n %y' -- ./report.txt
人向け時刻とoffsetを一緒に取得します。
epoch秒で比較
stat --format='%Y %n' -- ./report.txt
script判定ではlocale依存のdate文字列をparseしません。
UTCへ変換
epoch=$(stat --format='%Y' -- ./report.txt) && date --utc --date="@$epoch" --iso-8601=seconds
取得と変換の双方が成功した場合だけ記録します。
timestampsを一覧
stat --format='mtime=%y ctime=%z birth=%w' -- ./report.txt
ctimeをcreation timeと誤記しないよう並べます。
directory直下をmtime順に確認
find ./reports -maxdepth 1 -type f -printf '%T@ %p\n' | sort -n
同値時刻や特殊file名を考慮し、表示用途に限定します。
更新日時を比較へ使う設計
mtimeはcontentの最終変更、ctimeはinode statusの最終変更、birthtimeはfilesystemが対応する場合の作成時刻です。copyやarchive展開がmtimeを保持・再設定する場合があり、fileがその時刻に作成されたとは限りません。network filesystemではclock skewも考慮します。
%yの小数秒精度はfilesystemやkernel経由で見える精度に依存し、末尾のoffsetは表示したhostのtimezoneです。同じ瞬間でもUTC表示とlocal表示は文字列が違います。比較表ではISO表示だけでなく%Y、size、inodeを併記し、mtimeとctimeの差から『内容変更』と『metadata変更』を安易に逆算しないよう列定義を残します。
時刻が未来の場合は不正更新だけでなく、書込み元hostのclock、archive内の保存日時、timezone変換を確認します。小数秒が丸められるfilesystemでは短時間に連続した更新の順序をmtimeだけで確定できません。Permission denied、broken symlink、処理中に置換されたpathは別の失敗状態です。0や現在時刻へ補正して後続へ渡しません。
未来時刻・精度丸め・broken linkを識別する
- mtimeを作成日時と呼ぶ
- ctimeをcreation timeと解釈する
- copy先でも必ず同じmtimeと思う
- 秒未満精度を切り捨てて同一とする
- local time文字列を異なるtimezone間で比較する
statの空出力を未更新と解釈せず、missing path、broken link、権限不足をstderrとstatusで分けます。表示精度の丸めだけが疑われる時は%Yとfixtureの期待値を照合し、touchで本番時刻を直しません。
touchせずに更新履歴を保全する
時刻確認のためにtouchで値を合わせません。変更が必要なmigrationでは元のepoch値、timezone、hash、ownerを保存し、copy側で検証してから扱います。mtimeだけを信頼して悪意あるfileの新旧を判断しません。
mtimeを合わせる目的で本番へtouchを実行すると、backup、build、同期、監視の判定を変えます。表示調査と時刻変更を同じ手順にせず、修正が必要ならownerと影響するjobを特定して承認を得ます。原本へ変更を加えず、必要な検証は隔離したcopyで行い、復元は信頼できるbackupのmetadata保持手順で確認します。
時刻差を検証して運用へ載せる
content変更、chmod、rename、copy、archive展開の前後でmtime/ctime/birthtimeを記録します。hashと時刻を組にして、どの操作がどのtimestampを変えたか期待表と照合します。
test copyで内容変更、chmod、rename、copy -p、archive展開を分け、各操作前後の%y、%z、%Y、size、inodeを採取します。期待表では、内容変更でmtimeが動くこと、mode変更ではctimeだけが動くこと、保持copyではmtimeが引き継がれることを確認します。実運用ではapplication logやversion管理commit時刻とも照合し、同一sourceだけの二重表示を避けます。
epoch・inode・sizeで更新snapshotを出力する
scriptではlocale文字列を直接sortせず、%Yを整数として取得し、pathにnewlineがあり得る場合はNUL区切りを選びます。『更新なし』を検出する基準は取得時刻との差だけでなく、clock同期、許容精度、対象timezoneを固定します。fileが取得途中に置換された場合を検知するため、前後でdevice・inode・sizeを再取得し、一致しなければ再評価します。
deploy freshnessと改ざん検知を分ける
deploy freshness、cache invalidation、増分backupではmtimeが有用ですが、改ざん検知にはhashやsignature、作成経路の証跡が必要です。directoryの変更追跡にはwatcherやaudit log、database recordの方が適する場合があります。時刻比較の目的を『表示』『期間抽出』『完全性確認』へ分け、mtimeだけで足りない目的を別のmetricへ渡します。
合格条件は同一inodeの%YがUTC変換値と一致し、fixtureの古い・同じ・新しいを正しく並べられることです。clock異常または対象置換を検出したrunは無効化して再収集します。

コメント