Node-RED の JSONata で月の初日と最終日を取得するメモ
この記事は 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 でも似たアプローチができて満足です!