search
LoginSignup
14

More than 1 year has passed since last update.

posted at

updated at

Node-RED の JSONata で日付と時間をうまく扱える Tips

この記事は Node-RED Advent Calendar 2020 1日目の記事です。

いよいよスタートです!参加される、Node-RED UG のみなさまよろしくおねがいします!

今年もアドベントカレンダーはじまりましたね!

Node-RED の JSONata 機能について

以前も enebular で使える JSONata 式の便利 Tips といった記事を書いておりまして、Node-RED における JSONata の便利さを日々感じています。

詳しくは、英語ですが

JSONata Documentation · JSONata

こちらのドキュメントを見てみてください。

image.png (89.8 kB)

試してみるときは同サイトにある JSONata Exerciser もおすすめです。

その中でも日付と時間の扱いが便利

そう。Node-RED で、いろいろなデータを加工したり分析したりしますが、日付と時間をうまく扱いたいときって多いですよね・

たとえば、こういうとき。

  • CSVやデータベースから日時を抽出したあと扱いやすいようにタイムスタンプ(1970年からのミリ秒)に直す
  • タイムスタンプ(1970年からのミリ秒)からメール文面に使うイイ感じの表記にしたい
  • サーバー内で時差を考慮しない UTC の時間になっているけど JST に変更にしたい

もちろん、function ノードで Date 関数を駆使してがんばれなくはないんですが、ちゃんとコードで書ききるって結構大変なんですよね。 Date.getMonth 関数が 0 はじまりで 1 足さなきゃいけなかったり、表記に合わせて 2 月を 02 として 0 で埋めたり文字列処理も絡んできます。

image.png (43.8 kB)

ということで、 JSONata で使ってて気持ちよかったユースケースを紹介します。

現在の時間を基準に30日前のISO 8601形式のタイムスタンプの文字列にする

image.png (11.0 kB)

このようなフローです。

[{"id":"b1120bcb.6c0148","type":"inject","z":"6604f6d3.1fe9c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":200,"y":440,"wires":[["181a572a.6cc589"]]},{"id":"181a572a.6cc589","type":"change","z":"6604f6d3.1fe9c8","name":"30日前に変換","rules":[{"t":"set","p":"payload","pt":"msg","to":"$fromMillis($millis() - 86400 * 1000 * 30)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":440,"wires":[["443ee7dc.446578"]]},{"id":"443ee7dc.446578","type":"debug","z":"6604f6d3.1fe9c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":680,"y":440,"wires":[]}]

インポートできるフローJSONです。

image.png (23.3 kB)

change ノードの中はこのようになっています。

$fromMillis($millis() - 86400 * 1000 * 30)

$millis() 現在の経過ミリ秒。それを取得したあと - 86400 * 1000 * 30 で30日前にしたのち、fromMillis は経過ミリ秒を表す数値を、ISO 8601形式のタイムスタンプの文字列に変換してくれます。

image.png (4.4 kB)

実行してみると、このように "2020-10-31T08:12:44.044Z" ISO 8601 形式のタイムスタンプで出力されます。

現在の時間を基準に年月日だけ取り出す

image.png (10.5 kB)

このようなフローです。

[{"id":"453f393a.0eca18","type":"inject","z":"6604f6d3.1fe9c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":200,"y":520,"wires":[["e6d3c723.d37ec8"]]},{"id":"e6d3c723.d37ec8","type":"change","z":"6604f6d3.1fe9c8","name":"年月日だけ抽出","rules":[{"t":"set","p":"payload","pt":"msg","to":"$fromMillis($millis(),'[Y0001]/[M01]/[D01]')","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":520,"wires":[["edd80992.7ec3e8"]]},{"id":"edd80992.7ec3e8","type":"debug","z":"6604f6d3.1fe9c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":680,"y":520,"wires":[]}]

インポートできるフローJSONです。

image.png (23.8 kB)

change ノードの中はこのようになっています。

$fromMillis($millis(),'[Y0001]/[M01]/[D01]')

$millis() で取得した現在の経過ミリ秒を $fromMillisの第2引数で日時のフォーマットをかけています。今回は、年4桁・月0埋めの2桁・日0埋めの2桁のフォーマットです。

image.png (3.5 kB)

実行してみると 2020/11/30 と出力されます。

image.png (60.6 kB)

フォーマットについてはこのように XPath/XQueryで使われている日時フォーマット を利用しているので、気になる方は参考にしてみてください。

時差の処理や時差の表記を加える

サーバー時間がUTCになっているけど、日本時間が欲しいといったような時差の扱いってややこしいです。こちらも、かゆいところに手が届きます。

image.png (9.8 kB)

このようなフローです。

[{"id":"2bbc92ac.a336ae","type":"inject","z":"6604f6d3.1fe9c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"2020-11-01T00:00:00Z","payloadType":"str","x":180,"y":600,"wires":[["6e05fb54.0b8ec4"]]},{"id":"6e05fb54.0b8ec4","type":"change","z":"6604f6d3.1fe9c8","name":"時差 +9:00","rules":[{"t":"set","p":"payload","pt":"msg","to":"$fromMillis($toMillis(payload),'[Y0001]/[M01]/[D01] [H01]:[m01]:[s01] [z]','+0900')","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":600,"wires":[["7d950870.daf188"]]},{"id":"7d950870.daf188","type":"debug","z":"6604f6d3.1fe9c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":680,"y":600,"wires":[]}]

インポートできるフローJSONです。

inject ノードから 2020-11-01T00:00:00Z の文字列が来ると、 change ノードで、日本時間ぶんの時差+9:00を行って、時差のGMT表記も加えます。

ちなみにISO 8601形式のタイムスタンプで最後にZがつくとUTCを示します。→参考:ISO 8601 - Wikipedia

image.png (24.4 kB)

change ノードの中はこのようになっています。

$fromMillis($toMillis(payload),'[Y0001]/[M01]/[D01] [H01]:[m01]:[s01] [z]','+0900')

$fromMillis の第3引数は +0900 という表記で時差を設定できます。また $toMillis(payload) で inject ノードから来た 2020-11-01T00:00:00Z という文字列を ISO 8601 形式で解釈してミリ秒に置き換えているのも便利なポイントです。

image.png (4.5 kB)

実行してみると、このように "2020/11/01 09:00:00 GMT+09:00" と9時間の時差が処理され、GMT+09:00[z] というフォーマット記述によって引き出されています。このあたり、JavaScriptでできなくもないですが、ライブラリを使わないと、結構深い処理なので JSONata で書けるのはありがたいです。

明日は

明日の Node-RED Advent Calendar 2020 の担当は kitazaki さんの「Node-RED x Sonos x MINI LED Badge」です!

楽しみです!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
14