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 秒」という時間を表す時刻である、と解するのは難しいな。