コマンドで二つの時間の差分を取る方法

%H:%M:%S形式で二つ時間がかかれているファイルから、その二つの時間の差を取得する方法を考える。用途としては、ログファイルからstartとendの時刻を取り出し、その差分を計算するなど。

dateコマンド、awkのmktime、rubyのTimeを使う方法をそれぞれ見ていく。
dateコマンドが一番簡単で、rubyも同程度に簡単だが、時刻をパースして日時オブジェクトを作る際に、awkだけ書式に柔軟性がないため冗長になった。

dateコマンドを使う場合

date --date STRING +FORMATでSTRINGで指定された日付を作成し、FORMATで指定指定された形式で出力できる。STRINGに時刻を渡す。FORMATに%sを指定することでepoc timeを出力するので、整数計算に使用する。最後に計算する前にxargs -n2をすることで、計算に使う文字をまとめてawkに渡している。

次でawkのTime関係の関数を使うので、単なる四則演算だけだとしてもawkを使わずに上のコマンドを書き換えてみる。
初めに計算を簡単にするため、time.txtをcatではなくtacで反対から読む。
sedで計算式を作り、算術コマンドに使う。expr$(())の二パターンで計算してみる。

awkを使う場合

awkのmktimeを使ってTimeを作り、計算する。mktimeはmktime("yyyy mm dd HH MM SS")で実行できる。mktimeで加減算を行うと、epoc timeとして整数での計算ができるし、printしてもepoc timeが出力される。
はじめは簡単にするため、"yyyy mm dd"の部分を"2017 01 01"固定にする。

固定にした日付を現在年月日を使うように書き直してみる。現在時刻をmktimeの引数の"yyyy mm dd "部分に使うにはstrftime([format [, timestamp [, utc-flag] ] ])を使用する。

分を出すために60で割っているので、小数点が出てしまう場合があり、整数にしたければ、int()を呼ぶ。

ちなみにxargs -n2を使って計算に使う項をひとまとめに渡さない場合、2行目 - 1行目の計算をしなくてはいけない。三項演算子を使い、1行目であれば負数に、2行目であればそのまま正数にすることで計算しており、少しトリッキーになるが参考のため記載する。

Rubyを使う場合

TimeクラスとTimeライブラリを使う。Time.parse(date, now = Time.now)で文字列を変換してTimeクラスを作成してくれる。
readlinesで標準入力を配列で読んで、各行をパースし、引き算に帰結させている。
2行目から1行目を引かなければいけないので、配列をreverseする方法と、標準入力に渡す時にcatではなくtacであらかじめ逆転させる方法の二通りがある。

整数にしたい場合はtoiを呼ぶ。toiを呼ぶ個所は、60で割った計算結果に対してでも問題ないが、そもそも計算結果が浮動小数点になるのは、Timeを加減算した結果が浮動小数点なので、reduce後にto_iしてもいい。

-Linux, Ruby
-, , ,