NR runs on wrong time zone

Hi,

My node-red installation seems to run on UTC/GMT time zone, but should run on GMT+1.

In a function node, new Date() returns UTC time, I would expect the time for my timezone.

Also a call like new Date("2025-02-23T00:30:00+01:00") ends up in "2025-02-22T23:30:00.000Z"

NR runs on a standard raspberry PI installation with correct time setup:
pi@openWB:~ $ timedatectl
Local time: So 2025-02-23 18:23:28 CET
Universal time: So 2025-02-23 17:23:28 UTC
RTC time: n/a
Time zone: Europe/Berlin (CET, +0100)
Network time on: yes
NTP synchronized: yes
RTC in local TZ: no

pi@openWB:~ $ ls -l /etc/localtime
lrwxrwxrwx 1 root root 33 Nov 14 2018 /etc/localtime -> /usr/share/zoneinfo/Europe/Berlin

I found many entries regarding this problem, but they all were related to container setups.

What am I doing wrong? How do I setup the system correctly?

Many thanks

Heinz

If you are using Docker then possibly you have not setup the timezone for the container.

Otherwise run the command date in an exec node and see what it says.

Also. How are you converting the Date object to a string?

Hi Colin, I am NOT running docker. I run it directly on y raspberry PI.

Hi Colin,

Pls find my test code below:

[{"id":"b7956b295ed6e74e","type":"function","z":"e5d3ab09d5f02984","name":"Start/Stop charging","func":"//this function gets the charging start- and endtime from global variables\n//and initiates the charging accordingly\n\nconst ChargeParam = global.get(\"GoogleInstructions\"); //get instructions from Google Sheet set in flow \"Energymanagement\"\nconst ChargingStartTime = new Date(ChargeParam[11][1]);\nconst ChargingEndTime = new Date(ChargeParam[12][1]);\nconst OffPeakStart = new Date(ChargeParam[2][1]);\nconst OffPeakEnd = new Date(ChargeParam[3][1]);\nconst ChargingAmps = parseInt(global.get(\"ChargingAmpsFast\"));\nconst SoC = flow.get(\"%SoC_HG2\");\nconst LowerSoC = [1,2,3,4,5]; //Mo-Fr we need lower SoC than during Weekends\nvar CurrentTime = new Date();\nvar CurrentWDay = CurrentTime.getDay(); //current week day (Sunday = 0)\nvar TargetSoC = 0; //Desired state of charge of the car battery\n\nif (LowerSoC.includes(CurrentWDay)) {\n    TargetSoC = 60; //during weekdays\n} else {\n    TargetSoC = 80; //during weekends\n}\n\n\nmsg.payload = [CurrentTime, OffPeakStart, OffPeakEnd,ChargingStartTime, ChargingEndTime];\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":380,"wires":[["0571a1cf3794f48b"]]},{"id":"3466562e936a4387","type":"inject","z":"e5d3ab09d5f02984","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":380,"wires":[["b7956b295ed6e74e"]]},{"id":"0571a1cf3794f48b","type":"debug","z":"e5d3ab09d5f02984","name":"debug 60","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":660,"y":380,"wires":[]}]

The output from the debug node is as follows (first line is currente time which was 19:28):

["2025-02-23T18:28:17.221Z",
"2025-02-23T20:00:00.000Z",
"2025-02-24T06:00:00.000Z",
"2025-02-24T01:30:00.000Z",
"2025-02-24T04:00:00.000Z"]

The input is from a Google sheet as follows in the same order:

|OffPeakStart|2025-02-23 21:00:00|
|OffPeakEnd|2025-02-24 07:00:00|
|EVChargingStarttime|2025-02-24T02:30:00+01:00|
|EVChargingEndtime|2025-02-24T05:00:00+01:00|

Many thanks for looking into the issue.

Heinz

And the output from an exec node running date?

I can't look at the flow at the moment. Try using toISOString() to convert a Date object to string.

this IS 19:28:17 in GMT+1. It is a ZULU (UTC) representation of 19:28:17. Thats how date/time works.

If you want to be sure, call .toLocaleString()

I assumed that the OP understood that, but was concerned that the timezone embedded in the Date object is not the local timezone of the machine.

Is not the problem with toLocaleString() that it will force it to display in the local timezone even if the timezone embedded in the Date object is not that zone? I think that toISOString() will show the embedded timezone, which I assumed is what the OP is concerned about.

Edit, corrected above as it is rubbish. See later posts.

The output of toISOString() is always in UTC (docs).

I don't think there's an easy way to do this without resorting to some string-mangling or external libs like moment or dayjs. :confused:

Yes, you are right, I will correct my post above.

@ruffieuxh What do toString() and getTimezoneOffset() give you when called on your Date object?

Hi Colin,

Many thanks for looking into my issue again.

Current local time was 24.2.2025, 14:07:28

Output of toString():
Mon Feb 24 2025 14:07:28 GMT+0100 (Mitteleuropäische Normalzeit)

Output of getTimezoneOffset():
-60

So, this seems to be allright. Let me clarify my issue/question a bit:

  • When I enter "date" on the raspberry PI it always provides the time using the local time zone. Thi actually is true for any OS I know.

  • Therefore I would expect the system, based on my node example above, to provide the time using the local timezone as well

  • When I am using a constant like this:
    const ChargingStartTime = new Date("2025-02-24T01:30:00+01:00"),
    how can I be sure that the related action really get's executed at 01:30 and not on 00:30 when
    msg.payload = ChargingStartTime; results in 00:30 using a debug node without any conversion in between?

In essence: I would expect the time sent to a debug node would always be in local timezone.

What do I miss?

Many thanks again
Heinz

I wanted you to run it from an exec node in order to confirm that the environment node red is running in the correct timezone.

Which versions of node-red and nodejs are you using?
You can see the latter at the bottom of the dropdown menu in the node-red editor. The version of nodejs will be shown by the command node -v
Are you running the browser on the same machine that is running node red? If not then check the timezone of the machine running the browser.

Lets try and simplify it to work out what is going on. What does this flow show in the debug pane?

[{"id":"dc47ca3c28d08410","type":"inject","z":"bdd7be38.d3b55","name":"Go","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":360,"y":4800,"wires":[["fc32369d91999166"]]},{"id":"fc32369d91999166","type":"function","z":"bdd7be38.d3b55","name":"Now","func":"msg.payload = new Date()\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":560,"y":4800,"wires":[["aba3f509497d70ed","1e13fe4f8e18ca49"]]},{"id":"aba3f509497d70ed","type":"debug","z":"bdd7be38.d3b55","name":"Date","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":730,"y":4740,"wires":[]},{"id":"1e13fe4f8e18ca49","type":"function","z":"bdd7be38.d3b55","name":"toString()","func":"msg.payload = msg.payload.toString()\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":4800,"wires":[["79edfa9e17581b5f"]]},{"id":"79edfa9e17581b5f","type":"debug","z":"bdd7be38.d3b55","name":"toString","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":890,"y":4800,"wires":[]}]

Again, many thanks Colin,

Versions:
pi@openWB:~ $ node -v
v16.20.2

Node-Red: V3.1.9

Results from your nodes executed at 24.2.2025, 16:25:55:

Node Date: Mon Feb 24 2025 16:25:55 GMT+0100 (Mitteleuropäische Normalzeit)

Node toString(): Mon Feb 24 2025 16:25:55 GMT+0100 (Mitteleuropäische Normalzeit)

Now, I am officially confused... :slight_smile: This is is fact what I would expect.

Digging a bit further into it, I found out, that there is a 1 hour difference between this:

  • msg.payload = [new Date()]; and this

  • msg.payload = new Date(); //without brackets

Any explanation why that happens?

For my application I write sometimes to a Google Sheet and there I need to write in form of arrays of json.

Heinz

Evidence please. Replace the Function nodes with

msg.payload = [new Date()]
return msg;

and

msg.payload[0] = msg.payload[0].toString()
return msg;

I think you will find they are the same time, but one is showing it in local time, and one in UTC. That is just a quirk of the way the debug pane works in the browser. If the payload is a Date it is cleverer at displaying it.

ok, your node "now" is now set to:

msg.payload = [new Date()];
return msg;

and your node "toString()" is set to:

msg.payload[0] = msg.payload[0].toString();
return msg;

This results in the following output:

24.2.2025, 17:54:04[node: Date]
msg.payload : array[1]
0: "2025-02-24T**16:54**:04.269Z"

and

24.2.2025, 17:54:04[node: toString]
"Mon Feb 24 2025 **17:54**:04 GMT+0100 (Mitteleuropäische Normalzeit)"

Strange....isn't it?

Heinz

Not really.
As has been said before, 16:54 UTC and 17:54 GMT+0100 are the same time. There is no difference between them other than the way they are displayed. As I said, it is a quirk of the debug pane output that if msg.payload is a Date object then it displays it in the local time, but if the Date object is embedded then it displays it as UTC, but as I said, they are the same time.

If one were to look into what is actually in a Date object then one would see that it stores it as the UTC time, with, in addition, a timezone spec which just means "if you want to display this in local time of the creator then use this timezone".

1 Like

If it is a date in the debug panel you can click on it to display it in different formats

That was what I thought, but for me that seems not to be working any more.

It has to be a date not a string. ( though I think it also works for numbers that “look like” they are epoch like. )

1 Like

Of the three timestamp inject formats, it works for "millisec since epoch" but not for "javascript date object" or "YYYY-MM-DDTHH:mm:ss.ssssZ"

If you inject a number eg 174040000000 (current timestamp is an order of magnitude larger) then clicking the value alternates between decimal and hex but no datetime formats.