date コマンドが辛かったので、自分的最強日付時刻取り扱いコマンドを作りました。
以前、以下のようなぼやきを書きました。
もう 5 年以上前になるんですね。
その後も、ときどき date
コマンドの辛さを味わっては何とかしたいと思い続けて来ました。
一方、今年の夏、私は fq
というコマンドに出会いました。
この fq
自体は、date
コマンドとは何の関係もありません。jq
のようなフィルタ構文を使ってバイナリファイルの解析ができるという超便利なツールです。
<自慢>
ちなみに私はこの
fq
で WASM のバイナリが解析できるようにするためのプルリクエストを送ってマージされました。😤</自慢>
jq
の構文を JSON の操作以外のことに使ってもいいんだということに fq
のおかげで気付くことができて、しかもそれがかなり強力なものであるということがわかりました。
ちなみに
fq
の作者の wader さんは、jq で jq を実装するという意味のわからないことをしている人でもありますw
で、この fq
が jq
っぽいことができているのは gojq というパッケージのおかげだということを知りました。
gojq
はライブラリとして Go のプログラムに比較的かんたんに組み込むことができそうでした。
ここまで来たときに、「もしかして、日付や時刻を表すさまざまな表現を jq
のような構文でゴニョゴニョできたらめっちゃ便利だったりしないかな?」という妄想が私の脳の片隅に浮かびました。
たとえばこんな感じです。
$ echo 1669872594 | dq 'from_unix | add(72 | hours) | to_rfc3339' "2022-12-04T14:29:54+09:00"
すなわち、数値や文字列など何らかの形式で日付時刻を表すデータが標準入力から与えられた時に、それを元に「日付時刻オブジェクト」のようなものを内部的に生成し(上の例では Unix 時刻 1669872594
を与えているので from_unix
で Unix 時刻から「日付時刻オブジェクト」を生成している)、必要に応じて計算を行って(上の例では add(72 | hours)
で 72 時間後の時刻を計算)、それを任意の形式で出力(上の例では RFC 3339 の形式の文字列に変換)する、というようなことが慣れ親しんだ jq
の構文でできるようになりそうです。
そんなわけで、開発したのがこちらです:
dq
コマンドをインストールすると、上の例がそのまま実行できます。
詳しい使い方は README を見ていただければと思いますが、我ながらとてつもなく便利なものを作ってしまったなと思っています。
たとえば、date コマンドつらい に書いた以下のようなこともクロスプラットフォームで同じ書き方ができるようになっています。
単に
date
コマンドを実行したときと同じ出力を得たい$ dq -r tounixdate Thu Dec 1 22:24:24 JST 2022
-r
オプションはjq
と同じで raw output すなわち文字列の周りのダブルクオーテーション"〜"
を省略します。tounixdate
という関数の名前はto
unix
date
という具合に分解されて、つまりdate
コマンドの標準のフォーマットに変換するものです。このコマンドには標準入力に何も与えていないので、デフォルト動作として現在時刻(コマンドを実行した瞬間の時刻)を表す time オブジェクトに対して関数が適用されます。
現在の日時を指定のフォーマット(ここでは
%Y-%m-%d
)で出力したい$ dq -r '.unix | strftime("%Y-%m-%d")' 2022-12-01
strftime
関数は実はjq
に元から備わっている関数で、gojq
を使っていると自動的に使えるようになっている関数の一つです。内部的には C 言語のライブラリ関数のstrftime()
を呼び出しているようです。なのでstrftime()
関数と同じフォーマット指定子を使うことができます。strftime()
関数には Unix time を入力する必要があるので、.unix
で現在時刻の Unix time を取得して与えています。昨日の日付を出力したい
$ dq -r 'add_date(0;0;-1) | tounixdate' Wed Nov 30 22:27:38 JST 2022
日時の加減は
add_date
関数、もしくはadd
関数を使います。(減算もadd_date
やadd
に負の値を与えて行います) 年月日を加減算したい場合はadd_date
を使うのが便利です。 時分秒を加減算したい場合はadd
を使うのが便利です。add_date
関数には 3 つの引数で「年」「月」「日」のそれぞれの差分を指定します。jq
の関数は引数の区切りがカンマではなくセミコロンです。(カンマは JSON の中などで使うので紛らわしいのでセミコロンになっているのかな?) つまりadd_date(0;0;-1)
は、年は変更なし、月も変更なし、日は-1
すなわち 1 日前を表します。add
関数にはduration
(期間)オブジェクトを渡す必要があります。duration
オブジェクトはhours
minutes
seconds
milliseconds
microseconds
nanoseconds
のいずれかの関数(いずれも整数を入力してduration
を出力する関数)を使って、3 | hours
のように生成します。
最低限自分が必要とした基本的な機能は実装してあるつもりですが、まだまだ機能的には足りていないと思うので今後も継続的に育てていこうと思います。
皆様からのフィードバックもお待ちしております!GitHub の Issue や Pull Request はもちろん歓迎ですし、bitbears-dev 名義は英語で活動しておりますが「日本語じゃないと無理ー」という方は Twitter で @bearmini 宛にメンションしていただければと!