こんばんは、北国のインフラエンジニアkirksenchoです。
先日うるう秒対策について頭の中に入っていた情報を吐き出してみたのですが、思いのほか沢山のアクセスとストックを頂いて驚いております。
タイムリーな話題だったので、割と興味を持っている方が多かったのかもしれません。
今回はそのうるう秒対策絡みの調査の副産物を、最近始めたGitHubにコミットしてみたので、ご紹介してみたいと思います。
今回のうるう秒では1秒挿入されるので、そのうるう秒通知を受け取らないようにすると、そのサーバだけ1秒時間が進んでしまいます。
1秒位ならntpdやchronydなどに任せて時間調整はできますが、ある程度時間がかかるので、任意にコマンドを発行してミリ秒単位で戻せたら、何かあった時に安心です。
でもlinuxコマンドのdateは、1秒単位で指定して時間を巻き戻す事はできますが、ミリ秒やマイクロ秒での指定はできなさそうです。
以下のように現在時間をミリ秒単位で表示する事はできるんですが。
date +"%Y-%m-%d %H:%M:%S.%3N"
※Nはナノ秒の事です。3を付けないとナノ秒で表示されます。
無いものは作ってしまえばいいだろう、という事で簡単なC言語で書いてみました。
とりあえず、プログラム実行する度に100ミリ秒づつ戻ればいいかなという事で、引数指定とかは作ってません。
# include <stdio.h>
# include <sys/time.h>
/* Rewind 100mili sec program */
int main(void)
{
struct timeval t0;
gettimeofday(&t0, NULL);
/* Display now time */
printf("Now time: %dusec\n", t0.tv_sec, t0.tv_usec);
if ( t0.tv_usec >= 100000 ) {
t0.tv_usec = t0.tv_usec - 100000;
} else {
t0.tv_sec = t0.tv_sec - 1;
t0.tv_usec = t0.tv_usec + 900000;
}
settimeofday(&t0, NULL);
/* Display after sub time */
gettimeofday(&t0, NULL);
printf("After sub 100mili seconds: %dsec %dusec\n", t0.tv_sec, t0.tv_usec);
return 0;
}
作りは簡単で、現在時間をgettimeofday()で取ってきて、そのエポックタイムから100ミリ秒引き算して、settimeofday()で設定してあげてるだけです。
if文が一個ある理由は、ミリ秒の端数が100ミリ秒未満だった時に、何も考えずに100ミリ秒引いちゃうと、構造体のusecが負の値になってしまうので、もし端数が100ミリ秒無かったら、構造体のsecから1秒引いてから、usecに逆に900ミリ秒足してあげたら結果的に100ミリ秒引いたことになるという調整をしているからです。
こうすることによって、このプログラムを実行する度に、サーバの時間が100ミリ秒づつ巻き戻っていきます。
最近はインフラ構築系のお仕事なので、プログラムを書く機会がグッと減ったのですが、たまにコマンドだけで実現できないという状況になると、堂々とプログラムが書けるので、ちょっと楽しくなっちゃいました。
プログラムって面白いですね。