jqコマンドで日付のフォーマット変更とタイムゾーン変更

2022年1月9日

jqコマンド

jq コマンドで日付を扱うときに、出力する日付のフォーマットを変更したり、タイムゾーンを UTC から JST に変更する機会があったので備忘録。jq Manual (Dates) に載っているコマンドを参考に整理したものになります。jq のバージョンは 1.6。

前回書いた集計方法の記事も併せてどうぞ。

jqコマンド
jqコマンドで集計 group by, max, sum, count

jq コマンドで集計(最大、合計、数、平均、並び替え)をする方法を紹介します。jq のバージョンは 1.6。 以前書いた ...

続きを見る

目次

  1. strptime() で受けて、strftime() でフォーマットする
  2. strptime() と strftime() で使えるフォーマット文字列
  3. ISO 8601 形式の場合は専用の機能が使える
  4. macOS の jq では、ミリ秒を perse しようとするとエラーに
  5. UTC から JST に変換
  6. strptime() のフォーマット文字列 %z に注意

strptime() で受けて、strftime() でフォーマットする

基本はこの形。日付文字列を strptime()で perse し、strftime() で format します。

jq -n '"2022-01-08 10:09:01 +0000" | strptime("%Y-%m-%d %H:%M:%S +0000") | strftime("%F %R")'
"2022-01-08 10:09"

strptime() と strftime() で使えるフォーマット文字列

strptime()strftime() で利用できるフォーマット文字列は man コマンドで確認ができます。

man strftime

OS のドキュメントを参照するように jq Manual (Dates) に書かれています。

Low-level jq interfaces to the C-library time functions are also provided: strptimestrftimestrflocaltimemktimegmtime, and localtime. Refer to your host operating system's documentation for the format strings used by strptime and strftime. Note: these are not necessarily stable interfaces in jq, particularly as to their localization functionality.

jq Manual (Dates)

上記ドキュメントの後半の Note: these are not necessarily ... のところに書かれているように、strptime()strftime() は特にローカライズ機能において、必ずしも安定したインターフェースではないとのこと。

macOS では %u%j がサポートされていないようです。

jq may not support some or all of this date functionality on some systems. In particular, the %u and %j specifiers for strptime(fmt) are not supported on macOS.

jq Manual (Dates)

まとめると strptime()strftime() は OS によって挙動が変わりそうなので、複数 OS で実行される処理を書く時はよく検証しましょう。

ISO 8601 形式の場合は専用の機能が使える

出力が ISO 8601 の場合は todate という専用の機能が使えるので、シンプルに書けます。

jq -n '"2022-01-08 10:09:01 +0000" | strptime("%Y-%m-%d %H:%M:%S +0000") | todate'
"2022-01-08T10:09:01Z"

入力が ISO 8601 の場合は fromdate

jq -n '"2022-01-08T10:09:01Z" | fromdate | strftime("%F %X")'
"2022-01-08 10:09:01"

macOS の jq では、ミリ秒を perse しようとするとエラーに

検証に使用した macOS Big Sur の strftime には、フォーマット文字列にミリ秒が無いので、ミリ秒を含む日付文字列を perse しようとするとエラーになってしまいます。

jq -n '"2022-01-08T20:49:07.336Z" | strptime("%Y-%m-%dT%H:%M:%S") | strftime("%F %R")'
jq: error (at <unknown>): date "2022-01-08T20:49:07.336Z" does not match format "%Y-%m-%dT%H:%M:%S"

ミリ秒が不要な場合は、以下のようにミリ秒だけ切り捨てることで perse のエラーを回避することができます。

jq -n '"2022-01-08T20:49:07.336Z" | split(".")[0] | strptime("%Y-%m-%dT%H:%M:%S") | strftime("%F %R")'
"2022-01-08 20:49"

UTC から JST に変換

ドキュメントによると、jq の日付関数は UTC として時間を扱うとのこと。

jq provides some basic date handling functionality, with some high-level and low-level builtins. In all cases these builtins deal exclusively with time in UTC.

jq Manual (Dates)

UTC を JST に変換するには、以下のように、一度 mktime で日付をタイムスタンプに変換し、9 時間後のタイムスタンプを計算してから日付フォーマットに戻します。

jq -n '"2022-01-08 10:09:01" | strptime("%F %X") | mktime + (60 * 60 * 9) | strftime("%F %X")'
"2022-01-08 19:09:01"

strflocaltime()という便利な関数もあります。作業マシンのタイムゾーンを使ってタイムスタンプをフォーマットしてくれます。こちらのほうが短く書けます。

jq -n '"2022-01-08 10:09:01" | strptime("%F %X") | mktime | strflocaltime("%F %X")'
"2022-01-08 19:09:01"

strptime() のフォーマット文字列 %z に注意

strptime()のフォーマット文字列に %z を使うと、perse 時に作業マシンのタイムゾーンに変換されてしまうので気をつけて使いましょう。

jq -n '"2022-01-08 10:09:01 +0000" | strptime("%F %X %z") | strftime("%F %X %z")'
"2022-01-08 19:09:01 +0900"

上記の場合は、このように %z を使わないようにすると想定どおりの動きになります。

jq -n '"2022-01-08 10:09:01 +0000" | strptime("%F %X +0000") | mktime | strflocaltime("%F %X %z")'
"2022-01-08 19:09:01 +0900"

-技術ブログ
-