Help making datetime conversion more user friendly

I have a flow to process calendar events from this scrape. It will return a local datetime in the form of YYYY-MM-DD HH:mm:ss.

This works for me but limited to "en-US" without modification. Input is ISO

let start = new Date(msg.payload).toLocaleString("en-US", { hour12: false });

let x = start.split(","); //split date and time
let y = x[0].split("/"); // split date
let z = `${y[2]}-${y[1]}-${y[0]}` + x[1]; //new string YYYY-MM-DD HH:mm:ss

msg.payload = z;
return msg;
[{"id":"a9e4921e7027d964","type":"debug","z":"0a325c35fc29f44e","name":"debug 179","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":650,"y":400,"wires":[]},{"id":"f5dbee9d71387bf9","type":"function","z":"0a325c35fc29f44e","name":"function 18","func":"let start = new Date(msg.payload).toLocaleString(\"en-US\", { hour12: false });\n\nlet x = start.split(\",\"); //split date and time\nlet y = x[0].split(\"/\"); // split date\nlet z = `${y[2]}-${y[1]}-${y[0]}` + x[1]; //new string YYYY-MM-DD HH:mm:ss\n\nmsg.payload = z;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":400,"wires":[["a9e4921e7027d964"]]},{"id":"e971c76b5dc4198c","type":"inject","z":"0a325c35fc29f44e","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"2024-04-26T20:00:00.000Z","payloadType":"str","x":240,"y":400,"wires":[["f5dbee9d71387bf9"]]}]

I would like to make the code I am using universal so that regardless of the users tz, the datetime is converted to local time in the proper format.


It may be easier to do this using a change node;

set msg.payload to

$moment(payload).tz('America/Los_Angeles').format("YYYY-MM-DD HH:mm:ss")

// input payload: 2024-05-04T10:00:00.000
// output payload: 2024-05-04 01:00:00
1 Like

If you don't want to handle things yourself, try out either the moment node or the $moment function in JSONata.

But there is generally no real need to do locale conversions in Node-RED itself, leave that to the browser. So process and store everything on the server end in UTC and convert to/from local when interacting with real people. It avoids a shed-load of hassle.


The output is being pushed into a calendar and there is no conversion, I have to send a converted date. In the scrape there are 13 different event types with several sub types that mostly need separate processing.

It's easier for me to handle the information in a function node rather than a fan of 13+ flows. I already have a basic function working but only for my locale. Eventually I'd like to be able to share it without the need to modify it.

Is there away to get a users tz from an environmental variable? If I could get the offset then make the adjustment to the UTC time. Send that toISOString() and strip T and Z from it.

Moment should be available in the fn node as well in newer versions of Node-RED, I keep forgetting that.

Certainly. This article shows how:

1 Like

Idk how many times I've been through js date methods and hadn't noticed getTimezoneOffset. Thanks for the help. My ruff final solution

let d1 = new Date(msg.payload);
let x = d1.getTime(); // convert payload to ms

let d2 = new Date();
let y = d2.getTimezoneOffset() * 60 * 1000; // get timezone offset to ms

let z = x - y; //tz adjust
let tt = new Date(z).toISOString(); // convert to ISO date
msg.payload = tt.replace("T", " ").replace(".000Z", "");

return msg;


Easy to miss for sure.

And if you are updating your knowledge, check out the INTL library as well as it provides a lot of date/time processing that you needed libraries for in the past, especially if you are using node.js v18+

1 Like