bc による時刻計算
5 億人の bc ユーザの皆さん。時刻どうやって計算してるんだろう。具体的にやりたいことは、ログに記録された時刻二つから経過時間を知りたい、ということ。
最初、lx2x という関数を作って
$ echo 'lx2x(131415)' | bc 47655
みたいなことをさせてみようと考えた。つまり 13:14:15 は一日のうちの 47655 秒目だよ、と。lx2x という名前は 60 進数から 10 進数というくらいの意味。だけど、date2x にして
$ echo 'date2x(2131415) - date2x(1041254); x2date(last)' | bc 118881 1090121
とできたほうがいいか。11/1 の 4:12:54 から 11/2 の 13:14:15 までは 118881 秒で、一日と 9 時間と 1 分と 21 秒だよ、ということ。関数 x2date が逆変換になる。
とここまで考えて、ふと、世の中の皆さんがそれくらいのことをやっていないはずはない。bc 単体でもできんじゃね、と調べてみた。
野利庵日録 を参考にさせてもらう。
3時間10分+1時間20分ー40分=230分(3時間50分) ~$ echo "ibase=10; obase=60; a=60; (3+1)*a+(10+20-40)" | bc 03 50
なるほど ibase, obase か。これで x2date に近いことは関数を定義しなくてもできる。
$ echo 'ibase=10; obase=60; 118881' |bc 33 01 21
時刻への変換ではなくあくまでも 60 進数だから「33 時間」になって「一日と 9 時間」にならないのは仕方ない。bc(1) によると、
ibase には、2 から 16 までが使用できます。 この範囲を越える値を ibase に代入しようとすると、 2 あるいは 16 を指定したことになります。 数の入力には、0-9 および A-F の文字が利用できます。
とのこと。まあそれも仕方ないよね。逆は同じように簡単にはいかない、ということだ。
ということで、date2x 関数と x2data 関数を作る価値はあり、と見たがいかが。
5 億人の bc ユーザからのコメントで大変なことになっちゃうかもしれませんね、このエントリ。
追記
GNU bc なら read 関数を使ってインタラクティブに開始時刻、終了時刻を得るようにすればいいな。そしたら
$ bc elapsed.bc from: 2131415 to: 1041254 118881 1090121
ってできるな。うん。これなら「なんで Perl 使って計算しないの」って言われないで済む。
追記 2009-11-20
「date コマンドだけで済むことに対して何やっているの」というコメントを受けて、date だけでできることを調べてみた。なるほど。
$ echo $((`date -d '1/2 13:14:15' '+%s'`-`date -d '1/1 4:12:54' '+%s'`)) 118881
こうでもいいわけか。
$ echo $((`date -d '1/2 13:14:15' '+%s'`-`date -d '1/1 4:12:54' '+%s'`)) "; obase=60; last" | bc 118881 33 01 21
これはどうなんだろう。
$ echo $((`date -d '1/2 13:14:15' '+%s'`-`date -d '1/1 4:12:54' '+%s'`)) | gawk '{print $1,strftime("%Y-%m-%d %H:%M:%S",$1)}' 118881 1970-01-02 18:01:21
「1970-01-02 18:01:21」が「一日と 9 時間 1 分 21 秒」という時間を表す時刻である、と解するのは難しいな。