Refining time format in string from X min to X h Y min

I have a sensor that provides the information in the following manner:

  • It will rain in 87 min
  • It will stop raining in 55 min
  • It will snow in 77 min
  • It will rain for 85 min

Minutes range from 1 min to 120 min. When minutes are between 60 and 119 I want the format to be:

  • It will rain in 1 h 27 min
  • It will stop raining in 55 min
  • It will snow in 1 h 17 min
  • It will rain for 1 h 25 min

Input is a string like the examples above. Any help will be appreciated.

Just in case somebody’s interested… I believe it can be polished though, there must be a better way of achieving this…

[{"id":"7c5d03f21879db51","type":"split","z":"683f8f9b.fcae9","name":"","splt":" ","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":2570,"y":3780,"wires":[["75fbc9f0e148640f"]]},{"id":"7af35f3b789a7ecb","type":"switch","z":"683f8f9b.fcae9","name":"get number","property":"payload","propertyType":"msg","rules":[{"t":"istype","v":"number","vt":"number"}],"checkall":"true","repair":false,"outputs":1,"x":2950,"y":3780,"wires":[["f01446eabae4d523"]]},{"id":"75fbc9f0e148640f","type":"change","z":"683f8f9b.fcae9","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"$number(payload)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":2740,"y":3780,"wires":[["7af35f3b789a7ecb"]]},{"id":"f01446eabae4d523","type":"switch","z":"683f8f9b.fcae9","name":"Which value?","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"120","vt":"num"},{"t":"btwn","v":"119","vt":"num","v2":"60","v2t":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":3,"x":3140,"y":3780,"wires":[["6c3e250fb295fa98"],["7e2c45d85535fbf2"],["1a39ddc65e65eed4"]]},{"id":"7e2c45d85535fbf2","type":"change","z":"683f8f9b.fcae9","name":"","rules":[{"t":"set","p":"messageHead","pt":"msg","to":"$substringBefore(message, $string(payload) & \" min\")\t","tot":"jsonata"},{"t":"set","p":"messageTail","pt":"msg","to":"$number(payload) = 60 ? \"1 h\" : \"1 h \" & ($number(payload) - 60) & \" min\"","tot":"jsonata"},{"t":"set","p":"message","pt":"msg","to":"messageHead & messageTail","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":3360,"y":3780,"wires":[["1a39ddc65e65eed4"]]},{"id":"6c3e250fb295fa98","type":"change","z":"683f8f9b.fcae9","name":"","rules":[{"t":"change","p":"message","pt":"msg","from":"120 min","fromt":"str","to":"2 h","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":3380,"y":3740,"wires":[["1a39ddc65e65eed4"]]},{"id":"1a39ddc65e65eed4","type":"debug","z":"683f8f9b.fcae9","name":"debug 46","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"message","targetType":"msg","statusVal":"","statusType":"auto","x":3560,"y":3800,"wires":[]},{"id":"5c44e59c86e9cfb4","type":"inject","z":"683f8f9b.fcae9","name":"It will stop raining in 120 min","props":[{"p":"payload"},{"p":"message","v":"It will stop raining in 120 min","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"It will stop raining in 120 min","payloadType":"str","x":2320,"y":3720,"wires":[["7c5d03f21879db51"]]},{"id":"0c72caf2430d9d6a","type":"inject","z":"683f8f9b.fcae9","name":"It will rain in 90 min","props":[{"p":"payload"},{"p":"message","v":"It will rain in 90 min","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"It will rain in 90 min","payloadType":"str","x":2350,"y":3760,"wires":[["7c5d03f21879db51"]]},{"id":"d480f7d9aff4e0ed","type":"inject","z":"683f8f9b.fcae9","name":"It will snow in 60 min","props":[{"p":"payload"},{"p":"message","v":"It will snow in 60 min","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"It will snow in 60 min","payloadType":"str","x":2350,"y":3800,"wires":[["7c5d03f21879db51"]]},{"id":"4750e8240852e38a","type":"inject","z":"683f8f9b.fcae9","name":"It will thunder in 30 min","props":[{"p":"payload"},{"p":"message","v":"It will thunder in 30 min","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"It will thunder in 30 min","payloadType":"str","x":2340,"y":3840,"wires":[["7c5d03f21879db51"]]}]

You can always do JSONata in one go with a code block. Still looks messy but at least it can be done in one node.

[{"id":"5655cdc0a14fae8a","type":"inject","z":"987b2e9d10a9bd13","name":"Text","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"It will do something amazing in 65 min","payloadType":"str","x":530,"y":4680,"wires":[["bb422c449946d1ea"]]},{"id":"bb422c449946d1ea","type":"change","z":"987b2e9d10a9bd13","name":"JSONata","rules":[{"t":"set","p":"payload","pt":"msg","to":"(     $a:=payload.$substringBefore(\" min\");     $b:=$substringBefore($a, \"in \");     $mins:=$substringAfter($a,\"in \").$number();     $hours:=$floor($mins/60);     $mins:=$mins%60;     $b & \"in \" & ($hours<1 ? $mins & \" min\" : $hours & \" h\" & ($mins>0 ? \" \" & $mins & \" min\" )) )","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":680,"y":4680,"wires":[["9e6ca8395c3f2216"]]},{"id":"9e6ca8395c3f2216","type":"debug","z":"987b2e9d10a9bd13","name":"debug 68","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":840,"y":4680,"wires":[]}]
(
    $a:=payload.$substringBefore(" min");
    $b:=$substringBefore($a, "in ");
    $mins:=$substringAfter($a,"in ").$number();
    $hours:=$floor($mins/60);
    $mins:=$mins%60;
    $b & "in " & ($hours<1 ? $mins & " min" : $hours & " h" & ($mins>0 ? " " & $mins & " min" ))
)

It sometimes is for instead of in. I just updated the first post to avoid further confusions.

You approach looks nice. Sadly it’s pretty much the same I did. I appreciate :slight_smile:.

With a loosely structured string, I don’t think that there is much else that can be done other than pick it apart and rebuild with the necessary changes.

Yes, I assumed the "in ". Should have used a regular expression match on the number (assuming of course that there is one and only one number in the string…)

(
    $parse:=$match(payload,/\d+/);
    $head:=$substring(payload,0,$parse.index);
    $period:=$parse.match.$number();
    $hours:=$floor($period/60);
    $mins:=$period%60;
    $head & ($hours<1 ? $mins & " min" : $hours & " h" & ($mins>0 ? " " & $mins & " min" ))
)

that’s what I was looking for :slight_smile:. I’ll have a look on how those $match $parse work. I appreciate.

$parse is just a variable name I used here, nothing more! JSONata allows for variables as $name, which can be bound to values, expressions, or functions.

$match() is a JSONata string function that takes a string and a to-match string which can be a regex. It returns an object (or an array of objects for multiple matches) giving the matched string and the index. Thus $parse.index will give me the index location of the match, so I can slice off the head of the string using $substring(), and $parse.match.$number() gives me the matched string which I turn into a number using $number().

The documentation (for $match()) is here:
http://docs.jsonata.org/string-functions#match

If you want to test or develop JSONata, then use the try.jsonata.org - amazingly you can also save and share your code, so here is my code already set up for you! You can edit the code (RHS) and also the input JSON (LHS)

https://try.jsonata.org/35vC6oUN6

1 Like