Formatting UTC time to local time and calculating “minutes until …” in Node-Red

Hi

I want to be able to say when the next bus arrives:

“The next bus is in 6 minutes”

Through an API call, I have a timestamp of when the bus will arrive, in UTC format such as 2020-01-11T06:37:00Z

In Node-Red and I think using the Date/Time Formatter, I want to be able to convert this to “in xxx minutes” and I’m stuck.

I’ve been looking at the “time to x” formatting at https://momentjs.com/docs/#/displaying/to/ but can’t figure it out.

Any suggestions welcome!

Have you tried the moment node in nodered ? It does exactly that…
If you give it that date and use the “timenow” option for the output it will give you “in 6 minutes” assuming the date is 6 minutes in the future :slight_smile:
GV

I’ve got the Moment node available and that’s what I intend to use, I’m just not sure how to writ e the output format correctly (that’s my problem :grinning:)

Add fromNow to the Output Format field

Ahhh, that was easy - thanks!

Now my next challenge, is to have 4 times stamps come in (for 4 scheduled buses) and to sort them into chronological order and de-duplicate

For example:

  • sensor.bus_scheduled_1 = 2020-01-11T06:37:00Z
  • sensor.bus_scheduled_2 = 2020-01-11T06:30:00Z
  • sensor.bus_scheduled_3 = 2020-01-11T06:30:00Z
  • sensor.bus_scheduled_4 = 2020-01-11T06:43:00Z

Bus 2 and 3 are coming at the same time (it may be the same bus) and they’re arriving first, followed by bus 1 and finally bus 4.

The output should be (assuming the current time is 6:20):

  • 2020-01-11T06:30:00Z (in 10 minutes)
  • 2020-01-11T06:37:00Z (in 17 minutes)
  • 2020-01-11T06:43:00Z (in 23 minutes)

This would involve de-duplicating bus 2 and 3 (less important) but re-ordering the arrival times.

And once they’re sorted, then the ‘fromNow’ could be applied to the outputs to humanise them.

Any thoughts on this? You’re both been super helpful :grinning:

Sorry for the half good hint!
Have you seen the “i” on the right panel? If you select a node, information on how to use it is displayed. You will see that some nodes have very good documentation. moment is one of those :slight_smile:
GV

Assuming that you have different sensors with states being the next time for the bus here is an option to do it:

[{"id":"8416324a.715df","type":"ha-get-entities","z":"d59703d6.87ebf","server":"d28c9492.f419c8","name":"","rules":[{"property":"entity_id","logic":"starts_with","value":"sensor.bus_scheduled_","valueType":"str"}],"output_type":"array","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":270,"y":3860,"wires":[["86534371.bebfa"]]},{"id":"2c38cae1.145406","type":"debug","z":"d59703d6.87ebf","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1130,"y":3860,"wires":[]},{"id":"43d20691.e89128","type":"rbe","z":"d59703d6.87ebf","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":770,"y":3860,"wires":[["750c897c.31a1b8"]]},{"id":"86534371.bebfa","type":"change","z":"d59703d6.87ebf","name":"","rules":[{"t":"set","p":"array","pt":"msg","to":"$sort(payload)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":3860,"wires":[["2c6ba8a.fb24158"]]},{"id":"2c6ba8a.fb24158","type":"array-loop","z":"d59703d6.87ebf","name":"","key":"al2c6ba8afb24158","keyType":"msg","reset":false,"resetValue":"value-null","array":"array","arrayType":"msg","x":620,"y":3860,"wires":[[],["43d20691.e89128","b452546f.4363e8"]]},{"id":"b452546f.4363e8","type":"function","z":"d59703d6.87ebf","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":3920,"wires":[["2c6ba8a.fb24158"]]},{"id":"750c897c.31a1b8","type":"moment","z":"d59703d6.87ebf","name":"","topic":"","input":"","inputType":"msg","inTz":"Europe/Paris","adjAmount":0,"adjType":"days","adjDir":"add","format":"fromnow","locale":"C","output":"","outputType":"msg","outTz":"Europe/Paris","x":940,"y":3860,"wires":[["2c38cae1.145406"]]},{"id":"375c100a.e985e","type":"inject","z":"d59703d6.87ebf","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":3860,"wires":[["8416324a.715df"]]},{"id":"d28c9492.f419c8","type":"server","z":"","name":"hassio","legacy":false,"hassio":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true}]

The node shown as “msg.array” is a loop node (node-red-contrib-loop-processing) and rbe node (node-red-node-rbe) is a way to filter identical output.

At the beginning of the flow, you may want want to reset the rbe node to make sure it starts without previous state memorized.

GV

Nearly there - your flow is imported and the rde node installed

Injecting the timestamp picks up the 3 entities via “get entities” but “set msg.array” gives this error

“Invalid JSONata expression: The single argument form of the sort function can only be applied to an array of strings or an array of numbers. Use the second argument to specify a comparison function”

Sorry for all of the hand holding :grinning:

Replacing the jsonata expression in the change node by

$sort(*.state)

should do the trick.
You can copy the output of the get_entities into http://try.jsonata.org to adjust it.
This is what I am using to create the jsonata stuff (I am not fluent in this one!)

GV

1 Like

Bingo! That’s perfect! Thank you so much!

I can now do the next bit when I can ask the Google Home when the next buses are scheduled to arrive.

Really appreciate your help :smiley: :smiley: :smiley: