Time zone in A-Z in Node-Red

I have seen a few different topics on time zone issues and solution here, and I thought if we can have a topic to summarize all the common problems. I think this is as much as a Javascript topic and Node-Red.

To make sure the time zone settings are correct, I assume I can create an inject node with a timestamp, or a function node with the below code and link it to a debug node. Once the information comes through in the debug, click twice on the timestamp to change the display mode to local time:


And it everything is good, the timestamp of the debug message should match with the timestamp in the payload.

If you are using Node-Red in the docker container: check that the TZ environment variable is set correctly, more here: Inject node time zones
If you are using moment, there is more details discussion here: Convert the time input to local time zone in node red through moment function

But what if I am using Node-Red on a custom IoT Gateway where I have no access to the settings.js, or don't have an influence on the time zone settings of the underlying OS? What would be the best options in the function node to adjust the time to a local timezone? Would that take care of DST?

I believe that will tell you about the timezone of the machine running the browser, not the machine running node-red.

OK, I may need to find more examples. I am helping out a chap in the US and I find it difficult that we are getting different results based on who is looking at the data.

To check the timezone on the server, you can use Date.getTimezoneOffset() which will give you the local timezone offset.

1 Like

OK, I will check that. So the timestamp measure the milliseconds past from 01.01.1970 GMT and it gets translated to the local timezone when I convert it to a "human readable format"?

1 Like

Yes, inside computers you should nearly always work in UTC and convert to local time when needed.

1 Like

Directly to the question, you can keep a calculated TZ offset in a global variable. Then, if you cannot adjust the TZ of the server, you can always manually adjust it in your flows.

For uibuilder, the server sends its timezone to the client which saves an offset in the browser in case that is important to the web app. Though I've just realised that I should possibly also do the reverse and send an offset back to the server in the standard metadata. Another thing to add to the backlog.

Time and date calculations are, as you almost certainly realise, horribly complex which is why it is important to work in UTC to avoid TZ and DST issues. Convert at point of input/output by humans.

I only got access to the system where I had the issue and new Date().getTimezoneOffset(); returns zero. So that means that the server is set to GMT, right?

I mean it is not a problem for me, but what is the best way of converting to local timezone at the end? I can easily add of substract offset * 60 * 60 * 1000 where offset if the hours ahead or behind UTC. And how I take DST into account?

When working on node.js or in a modern browser, INTL is your friend.

Intl - JavaScript | MDN (mozilla.org)

For conversion to local times though, you really want to do that in the browser since that is where the local tz is known. And the Date object has plenty of locale-specific conversions (which use INTL when it is available).

I don't have a problem in the browser. But I am exporting the data into a CSV file. At the moment, I just export the datetime in timestamp to the file. But when this information is imported into for example Excel, it comes up with the wrong date. That is what I want to correct.
I guess if I offset with a fix number of hours, it will be off again once we change into/out of DST.

I am afraid that I am overcomplicating this, but I added this code to a function node and it correctly return the time. I see the same time in debug what I see as local time (the time on the taskbar of the remote machine I work on):

// difference between the local time and GMT in hours. For UTC-5 it is -5.
var offset = -5;

function lastSunday(year, month) {
    var date = new Date(year, month, 1, 12);
    let weekday = date.getDay();
    let dayDiff = weekday === 0 ? 7 : weekday;
    let lastSunday = date.setDate(date.getDate() - dayDiff);
    return date;
}

function isDST(date) {
    var d1 = lastSunday(date.getYear(), 3); // last Sunday of March
    var d2 = lastSunday(date.getYear(), 10); // last Sunday of October
    return ((d1.getTime() <= date.getTime()) && (date.getTime() < d2.getTime()));
}

function UTCTimeStampToLocalDate(timestamp, offset) {
    var mydate = new Date(timestamp); 
    if (isDST(mydate)) { 
        offset++;
    }
    var newDate = new Date(mydate.getTime() + offset * 60 * 60 * 1000);
    var hours = mydate.getHours();
    newDate.setHours(hours + offset);
    return newDate;
}

msg.payload = UTCTimeStampToLocalDate(new Date().getTime(),offset).toLocaleString();
return msg;

If you let JavaScript convert to text, it should save it with the "Z" timezone so Excel or other tools should be able to convert at point of use by a person. Or if the CSV ends up in a DB or another system, you should be sticking with UTC anyway.

Ignoring DST.

If doing this in node.js, you don't need any custom functions I don't think.

let myutc = new Date()
return myutc.toLocaleString('en-US', { timeZone: 'EST' })

Gives the date/time in format local to Eastern Standard Time which is UTC-5.

This will take care of the occasional changes to DST swapovers and will deal with those awkward times that are on the swapover itself, usually 2am.

Thanks for the feedback. Currently the CSV stores the timestamp, but I will clarify how the CSV is process and change the output to LocaleString. Maybe that would make more sense and also makes importing to Excel easier.

In the next release of UIBUILDER, the client informs the server of its connection timestamp. The server compares that with its timestamp and if the 2 are >1 minute apart, this is reported in uibuilder messages on the server.

The code is completed and pushed to the v6.8 branch on GitHub.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.