TZif(zoneinfo)ファイル解析ツール
TZif ファイルはタイムゾーンをコンパイルしたものです。/usr/share/zoneinfo/Europe/Berlin にあるもの、TZ= が指すもの、JDK に同梱されコンテナイメージにコピーされるものが、まさにこれです。中身が見えず自分の名前も持たないため、あちこちにコピーされるのに確かめる手段がありません。このツールは RFC 8536 に沿ってファイルをブラウザ内で開き、実際に入っているものを表示します。ヘッダーのバージョンと 6 つのカウントは 2 つのブロック分を並べて示します。バージョン 2 以降のファイルは、まず 32 ビットブロックを丸ごと含み、その後に 64 ビットブロックを置くからです。前者は今のリーダーが読み飛ばす旧式部分で、slim なファイルではタイプ 1 個・遷移 0 件にまで削られ、本当のデータは後者に入っています。タイプ表にはオフセット、夏時間フラグ、略称に加えて、その規則が標準時と壁時計時刻のどちらで書かれていたかを示す標準/壁時計インジケータと UT/ローカルインジケータが並びます。遷移表には各切り替えの前後のオフセット、新しい略称、夏時間に入るかどうかが出ます。遷移時刻は符号付き 64 ビット秒なので、1901 年や 2037 年の日付、何も変えない番兵のエントリーが入っていても異常ではありません。POSIX フッターはそのまま写すのではなく項目に分解します。標準時と夏時間の略称、POSIX の反転した符号を戻した両方のオフセット、M・J・0 起算の開始終了規則を示し、基準年の実際の時刻まで計算します。slim なファイルでは、来年の春を説明するのはこのフッターだけです。うるう秒レコードは right/ ツリーのように実際に持つファイルでのみ表示されます。一方で、これがどのゾーンかは分かりません。TZif は自分の名前を持たず、別名ファイルは元と 1 バイトまで同一だからです。チェックサムもないため、途中の 1 バイトが化けても壊れたとは判定されず、遷移時刻が静かにずれるだけです。
使い方
- コンパイル済みのゾーンファイルをドロップしてください。/usr/share/zoneinfo からコピーしたもの、docker cp でコンテナから取り出したもの、JDK から取り出したものが使えます。
- まずサマリーを見ます。バージョン、遷移の件数、そして将来が列挙されている(fat)のか、POSIX 規則に任されている(slim)のか、固定なのかが分かります。
- ヘッダーの 2 列を見比べます。slim なファイルではほぼ空の 32 ビットブロックと中身の詰まった 64 ビットブロックが並びますが、これは破損ではなく設計どおりです。
- 基準時刻と次の遷移を見れば、このファイルが今日どのオフセットを返し、次にいつ変わるかが分かります。
- slim なファイルでは POSIX フッターの節を開いてください。最後の遷移より後の日付は、そこにある M・J・0 起算の規則だけで決まります。
よくある質問
- なぜヘッダーのカウントが 2 組あるのですか。
- バージョン 2 以降のファイルが本当にデータを二度持っているからです。まず遷移時刻が 32 ビットのバージョン 1 ブロックが丸ごと入り、その後に 2 つ目のヘッダーと 64 ビットブロック、最後に POSIX フッターが続きます。2004 年より前に書かれたリーダーが失敗せずに読めるようにするための構造で、RFC 8536 は現代のリーダーに 2 つ目のブロックへ飛ぶよう指示しています。だからカウントが違っていて構いません。zic の slim 出力では最初のブロックがタイプ 1 個・遷移 0 件まで削られ、本当のデータは 2 つ目に入ります。あるツールがこのゾーンには履歴がないと言うなら、たいてい旧式ブロックを読み違えており、いまだにそう動くライブラリもあります。
- fat なファイルと slim なファイルは何が違うのですか。
- 同じゾーンを表しますが、将来をどれだけ書き出すかが違います。fat は 2037 年までの全遷移を並べるので Europe/Berlin なら約 140 件入り、今年 10 月の切り替えも表から直接読めます。slim は規則から導けない最後の遷移で止め、その先を POSIX フッター文字列に任せるため、サイズが 10 分の 1 になることもあります。2020 年以降 zic の既定は slim ですが配布物によって異なり、Debian と Ubuntu は今も fat を配り、Alpine をはじめ多くのコンテナベースイメージは slim を配ります。フッターを無視するリーダーは fat では正しく動き、slim では来年を静かに間違えます。特定のイメージでだけ再現するバグの正体はたいていこれです。
- POSIX フッターはどう読み、M・J・数字だけの形式は何を意味しますか。
- フッターは TZ 環境変数に入れる文字列と同じ形式で、標準時の略称、標準時のオフセット、任意で夏時間の略称とオフセット、そして両者を切り替える 2 つの規則から成ります。オフセットは POSIX 流でグリニッジより西が正なので、CET-1 は UTC+01:00 を意味し、このツールは符号を戻して表示します。規則には 3 つの形式があります。Mm.w.d は月・週・曜日で、週が 5 なら最終週なので M3.5.0 は 3 月の最終日曜です。Jn は 1 から数える年内日で 2 月 29 日を決して数えないため J60 は常に 3 月 1 日です。数字だけの形式は 0 から数え 2 月 29 日を含むので、59 は平年なら 3 月 1 日、閏年なら 2 月 29 日です。最後の形式はまれで実装によって解釈が割れ、Python の zoneinfo は glibc より 1 日遅く解釈します。
- Etc/GMT+5 のオフセットがなぜ -05:00 と表示されるのですか。
- Etc 系の名前が POSIX の符号規約に従っており、それが他のあらゆる場所と逆だからです。TZ 文字列では正がグリニッジより西を意味します。したがって Etc/GMT+5 は UTC より 5 時間遅いゾーンで、ISO 8601 でも画面上でもそれは -05:00 と書きます。逆に Etc/GMT-5 が 5 時間進んだ側です。tz データベースは POSIX がその動作を要求するためこれらの名前を残しつつ、罠であると警告しています。このツールはオフセットを ISO 流で表示するので、名前が +5 でオフセットが -05:00 なのは矛盾でもバグでもなく、命名規約が表に出ているだけです。
- うるう秒レコードとは何で、right/ のファイルの遷移時刻はなぜ変に見えるのですか。
- tz データベースは 2 通りにコンパイルできます。タイムスタンプがうるう秒を含まない秒数である通常の posix/ ツリーと、1972 年以降のうるう秒をレコードとして持ち、タイムスタンプが実際の経過秒を数える right/ ツリーです。多くのシステムは前者しか配らないので、ここにうるう秒表が出るなら right/ のファイルか、誰かが zic -L でコンパイルしたファイルです。そうしたファイルでは遷移が累積補正の分だけずれ、01:00:00 のはずの切り替えが 01:00:27 と表示されます。1972 年以降に 27 回のうるう秒が挿入されたためで、補正の列も同じ 27 まで増えます。posix/ の時刻を前提とするシステムに right/ のファイルを混ぜると、ちょうど 27 秒ずれます。
- このファイルがどのゾーンか、また壊れていないかは分かりますか。
- どちらも分かりません。いずれも形式そのものの性質です。TZif ファイルは名前を持たず、ゾーンの同一性はデータベース内のパスだけから来ます。だから Asia/Istanbul のようなリンクは Europe/Istanbul と 1 バイトまで同じコピーかシンボリックリンクであり、内容では区別できません。できるのは略称・オフセット・遷移の日付という指紋からゾーンを見分けることで、ここの表はそのためにあります。形式にはチェックサムがどこにもないため、遷移表の 1 バイトが化けてもファイルは無効にならず、遷移が静かにずれるか別のタイプを指すだけです。検出できるのは長さがカウントと合わない場合だけで、このツールはそれを切り詰めとして拒否します。
関連ツール
タイムゾーン変換
サマータイムを含めて、2 つの世界のタイムゾーン間で日時を変換します。
SQLite データベース検査ツール
.sqlite や .db をブラウザーで開いて構造を読み取ります。ページサイズ、エンコーディング、ジャーナルモード、各テーブルの実際の行数まで。
世界時計
複数のタイムゾーンを並べて表示 — リアルタイム更新と現地時間との差分付き。
タイムゾーンを跨ぐ会議時間ファインダー
各参加者の勤務時間でタイムゾーンを追加し、24 時間オーバーラップグリッドを見て、全員のローカル時間でベストな会議スロットを読む。
DNS ゾーンファイル検証ツール
BIND のゾーンファイルを貼り付けると実際の意味がわかります。すべての名前を完全修飾で展開し、SOA を解説し、パーサーだけでは見つからない罠を指摘します。
Hex Dump ビューア
テキストまたは小さなファイルをオフセット + hex バイト + 印字可能 ASCII で表示。`xxd` や `hexdump -C` 形式。