この記事は Node-RED Advent Calendar 2021 の 5 日目の記事です。25 日ごろまで書かれず急に空いてしまったのでピンチヒッターです。
Node-RED の JSONata で月の初日と最終日を取得するメモです。
背景
たとえば、WordPress REST API にようなデータを取得する API で期間を与えて取得できるシーンがありますが、そのときに、その API の日付フォーマットに合わせて、ある月のデータが欲しくて初日0:00から最終日23:59まで取得したいときがあります。
初日はやりやすい
まず、初日0:00
ですね。
いろいろなやり方があるかなと思いますが、私の場合は JSONata の日付処理が使いやすいので、Node-RED の JSONata 記法でこのように書きました。
$fromMillis($millis(),'[Y0001]') & "-01-01T00:00:00"
こちらを実行すると、 $fromMillis($millis(),'[Y0001]')
で、いま実行している年、つまり今年が返ってきます。あとは、固定値 "-01-01T00:00:00"
がつながるので、
"2021-01-01T00:00:00"
といった値が取得できます。いままで、毎年1回だけ調査するような仕組みで、手打ちで年の部分を変えていたので、自動でできて便利。
最終日はこうしてみた
つづいて、最終日23:59
です。
月の最終日は、常に変動するので厄介です。各月をメモって固定値にすればいいかなと思いきや、うるう年の場合は2月が29日になったりして、地味にややこしいです。
なので、次の月の1日目の 0:00 から1秒だけ引いて 23:59:59 を表現することにしました。
$fromMillis( $toMillis( $fromMillis($millis(),'[Y0001]') & "-02-01T00:00:00" ) - 1000, '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]', '+0900' )
ちょっと、複雑なので、インデントした複数行で載せています。JSONataってこういう風にも書けるんですよね。
具体的には、
$toMillis( $fromMillis($millis(),'[Y0001]') & "-02-01T00:00:00" ) - 1000,
の部分が $fromMillis($millis(),'[Y0001]') & "-02-01T00:00:00"
で次の月の1日目を取得しています。
これで、2021-02-01T00:00:00
のような文字列が返ってくるので、$toMillis
を通すことでミリ秒に戻して – 1000 で1秒だけ引いて 23:59:59 のミリ秒を出すようにしました。
あとは、
$fromMillis( その月の最終日 23:59:59 ミリ秒, '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]', '+0900' )
となり、今回の場合はタイムゾーンを日本時間で扱いたかったため第3引数に '+0900'
を付与して '2021-01-31T23:59:59
と返ってきました。タイムゾーンまわりはサーバーで返すミリ秒によって色々あるかもしれないので、一度タイムゾーンなしで出力してみてどうなるかを、把握してから、行ったほうがいいと思います。
今回のフロー
簡単ですが、今回の知見を踏まえてこのようなフローを作りました。
[ { "id": "3cac569ea15acea0", "type": "inject", "z": "4a583c59761dbc44", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 230, "y": 200, "wires": [ [ "0161950bd7fc8f69" ] ] }, { "id": "0161950bd7fc8f69", "type": "change", "z": "4a583c59761dbc44", "name": "1月の初日と最終日を取得", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "[\t $fromMillis($millis(),'[Y0001]') & \"-01-01T00:00:00\",\t $fromMillis(\t $toMillis(\t $fromMillis($millis(),'[Y0001]') & \"-02-01T00:00:00\" \t ) - 1000,\t '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]',\t '+0900' \t ) \t]", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 490, "y": 200, "wires": [ [ "d5d37bd89abef353" ] ] }, { "id": "d5d37bd89abef353", "type": "debug", "z": "4a583c59761dbc44", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 750, "y": 200, "wires": [] } ]
実行してみると、配列の0番目に初日が、1番目に最終日が返ってきます。
最終日 23:59:59 を出すテクニック自体は JavaScript の Date クラスで頑張ったことはあるのですが、 JSONata でも似たアプローチができて満足です!