Linux をうるう秒対応にするための設定

うるう秒という物の存在をご存じでしょうか?例えば1999年1月1日 0時0分0秒(GMT) 前後の1秒ごとの協定世界時での時刻の変化を見てみましょう。

Thu Dec 31 23:59:58 GMT 1998
Thu Dec 31 23:59:59 GMT 1998
Thu Dec 31 23:59:60 GMT 1998  ←ここに注目
Fri Jan 01 00:00:00 GMT 1999
Fri Jan 01 00:00:01 GMT 1999
Fri Jan 01 00:00:02 GMT 1999
たぶん、普通のコンピュータのシステム時計は、
Thu Dec 31 23:59:58 GMT 1998
Thu Dec 31 23:59:59 GMT 1998
Fri Jan 01 00:00:00 GMT 1999
Fri Jan 01 00:00:01 GMT 1999
Fri Jan 01 00:00:02 GMT 1999
Fri Jan 01 00:00:03 GMT 1999
という感じで時を刻んでいることでしょう。
まあそれだけの話といえばそれだけです。何秒もずれているのが 当たり前のマシンでは、どうってことはないでしょう。 しかし、世の中には必要性があって、ある程度の精度で時刻同期を とっているマシンも存在するのですが、それらのマシンで、 うるう秒の挿入時に、1秒も時刻を戻してしまうというのでは、 時刻同期を取っている意味が無いですね。
そこで、うるう秒対応のシステムを構築したいという需要もある わけです。で、Linux の場合はどうかしらと調べてみると、 たまたま手元にあった glibc-2.1.3 のソースコードを見ると、 うるう秒に対応するためのコードが見つかりましたので(正しく 動作するかどうかまでは見ていません)、パッチを当てて、libc の 再構築といった大げさなことをしなくても、簡単な設定で 対応できそうでしたので試してみました。

それでは、試してみましょう。
その前に、これからやることを実行すると、何らかの問題が発生する 可能性があります。ディスクを破壊したりとか、そういう種類の障害は 原理上発生しないはずですが、時刻の関わるもの、 cron とか syslog 関係とか、そういうもので何か起こるかもしれません。できれば、テスト用 マシンを用意して十分検証した方が良いでしょう。 私の環境では、幸い障害は発生していません(今のところ....)。

用意する物
Linux のインストールされているマシン。
調べていないのでよく分かりませんが、glibc-2.1 以降でないとうるう秒の 処理に対応していないようです。glibc-2.1 を標準で採用している ディストリビューションを使用するのがよいでしょう。私は Plamo Linux 2.0 で実験しました。
timezone data
ftp://elsie.nci.nih.gov/pub/ から取得してください。 2003年4月25日現在、 ftp://elsie.nci.nih.gov/pub/tzdata2003a.tar.gz が最新の様です。 これらのアーカイブ内にあるうるう秒挿入日時のデータ leapseconds については、 うるう秒の挿入が決定される度に更新されますので、定期的に新しいものを取得 して、以下の作業をやり直す必要があります。

zoneinfo の作成。
今回は、/usr/share/zoneinfo 以下全てをうるう秒対応に変更するのではなく うるう秒対応の Asia/Tokyo の zoneinfo だけを作成する事にしますので、 上記 glibc のソースまたは tzdata2000d.tar.gz から

asia
leapseconds
というファイルだけを持ってきて下さい。 適当なディレクトリを作成して asia, leapseconds をコピーして
zic -d .  -L leapseconds asia
を実行すれば、カレントディレクトリの Asia 以下に、アジア各地のうるう秒に対応した zoneinfo が作成されます。 このファイルを /etc/localtime にすれば終わりです。
私の場合は、 Asia/Tokyo をファイル名を変えて、 /usr/share/zoneinfo/Asia/Tokyo-leaps という名前でコピーして
ln -s /usr/share/zoneinfo/Asia/Tokyo-leaps /usr/share/zoneinfo/localtime
ln -s /usr/share/zoneinfo/localtime /etc/localtime
という風にリンクを張りました。 /usr/share/zoneinfo/Asia/Tokyo にリンクを
張り直せば元の状態に戻ります。

後は、適当なプログラムを書いて実験してみてください。 たとえば、次のようなプログラムを実行すれば、

#include 
#include 

int
main()
{
        time_t t = 915148819;
        int    i;

        for( i = 0; i < 5; i++ ){
            printf( "%11.1d: %s", t, ctime(&t) );
            t++;
        }

        exit(0);
}
うるう秒に対応していれば、
  915148819: Fri Jan  1 08:59:58 1999
  915148820: Fri Jan  1 08:59:59 1999
  915148821: Fri Jan  1 08:59:60 1999
  915148822: Fri Jan  1 09:00:00 1999
  915148823: Fri Jan  1 09:00:01 1999
という結果になるでしょうし、対応していないシステムでは、
  915148819: Fri Jan  1 09:00:19 1999
  915148820: Fri Jan  1 09:00:20 1999
  915148821: Fri Jan  1 09:00:21 1999
  915148822: Fri Jan  1 09:00:22 1999
  915148823: Fri Jan  1 09:00:23 1999
となることでしょう(実行しているマシンのlocaltime が日本標準時に設定されている 場合です)。 ruby がインストールされていれば、
#!/usr/local/bin/ruby
#

t = Time::gm( 1998, 12, 31, 23, 59, 58 )

for i in 1 .. 5
        printf( "%11.1d: %s\n",t.to_i, t.to_s )
        t += 1
end
というプログラムなんかは如何でしょうか? 上記 ruby のプログラムでは、時刻の表示が GMT になっていますが t.to_s を t.localtime.to_s に変更すれば、local time 表示になります。

何か問題は起こるのか?
たぶん起こると思います。例えば、毎時 0分0秒に何かするというつもりで

	t = time(NULL);
	if( ( t % (60*60)) == 0 ){
		.......
というような書き方をされると困ったことになりますよね? 1972 年頃は 毎時 0分0秒だったの が、現在(2000年)では、希望よりも 22 秒早く実行されてしまいます。新規に作成する物に ついては、プログラムの作成者が気をつけていれば良いだけの話ですが、今使っている プログラムはどうなっているでしょうか? なんか 2000年問題の時の事を思い出しますね。

ところで次のうるう秒はいつでしょうか?それは、誰にもわかりませんが、 2003年7月1日にうるう秒が無い事は決定しているようです。 うるう秒の実施に付いての情報を早めに知りたい方は、 独立行政法人通信総合研究所 日本標準時グループ のページの「日本標準時グループからのお知らせ」をまめにチェックすると 良いでしょう。


このページに関する、ご意見、感想、苦情はこちらまで 松本 徳真 / matsu@netfort.gr.jp