Time Picker in ui_form node sends wrong time in output payload

Changing the type will of course break existing users…

can you explain that please @dceejay ?

Then maybe a note in the help section may help avoid confusion.

@e1cid suggested changed the output format from the current time object to raw milliseconds - so that users could then convert it how they liked... This would break any existing user of the node that it is working for until they then add the necessary conversion for their application. We don't really want to do that unless we really have to and would mean a major bump to dashboard from version 3 to version 4..

Thank you @dceejay . I totally understand that.

I found a code snippet and modified and added it to the function which I'm developing to process the form data.

var dateTime = msg.payload.Start

var myDate = new Date(msg.payload.Start);

var offset = myDate.getTimezoneOffset() * 60 * 1000;

var withOffset = myDate.getTime();

var withoutOffset = withOffset - offset;

node.warn(withOffset);

node.warn(withoutOffset);

duration = withOffset

milliseconds = parseInt(( duration % 1000) / 100)

seconds = Math.floor((duration / 1000) % 60)

minutes = Math.floor((duration / (1000 * 60)) % 60)

hours = Math.floor((duration / (1000 * 60 * 60)) % 24)

mess = hours + ":" + minutes + ":" + seconds

node.warn(mess)

duration = withoutOffset

milliseconds = parseInt((duration % 1000) / 100)

seconds = Math.floor((duration / 1000) % 60)

minutes = Math.floor((duration / (1000 * 60)) % 60)

hours = Math.floor((duration / (1000 * 60 * 60)) % 24)

mess = hours + ":" + minutes + ":" + seconds

The debug output shows that this works at this moment in time and probably up to 26 March 2023

Screenshot 2022-11-27 204339

I'm not sure if there is any way to test whether this really does work until we really have DST and UTC 00.00 but I think I'll use it until then

1 Like

You should add a comment node to the tab you are using this on and document what you did and why so in March next year if any issue comes up, you have something to jog your memory.

1 Like

In case anyone is interested I have found the cause of the confusion. In 1968, as I now remember, but had forgotten, the UK trialled year round daylight saving time. This trial lasted until 1971 and meant that London was permanently on DST or UTC+1. Hence, in the UK, the start of the epoch was at 01:00 local time.

2 Likes

Well $toMillis() is wrong as far as I can see. This code gives 57660000, as it should
msg.payload = new Date("1970-01-01T16:01:00.000Z").getTime()

Yes it seems to be the browser returning a date object that includes the time zone UTC+1 (when in uk) The html5 input doesn’t seem to have any options to change that so I’m not sure how we can adjust it.

Do you feel that the solution that I proposed above will stand the test of time and still work when we do have DST in effect and that the solution can only be applied at a developer level?

I think this is a simpler solution. The code

const time = new Date(msg.payload.time)
const msecLocal = time.getTime() - time.getTimezoneOffset() * 60000

gives the milliseconds since the start of the day local time, from which anything else can be calculated. I think that should work for any time zone, provided the server and browser are configured for the same zone. At the moment my brain has not been able to cope with considering the situation where the two timezones are different.
I have to go for the moment, but will think about the most efficient way to get the hours/mins/secs from that.

I think I already mentioned that in post 32 above.

Is it? or is it handling the year round UK DST in 1970 correctly?

If I put, in a Change node, Set msg.payload To JSONata $toMillis("1970-01-01T16:01:00.000Z") I get 57660000, which agrees with Date.getTime(). Where did you see $toMillis() give 61260000 for that timestamp?

In fact it is easier than I thought. This will give the hours and minutes as entered into the time picker

const time = new Date(msg.payload.Start)
// this is the number of milliseconds into the day, if needed
//const msecLocal = time.getTime() - time.getTimezoneOffset() * 60000
const hours = time.getHours()
const mins = time.getMinutes()
msg.payload = `${hours.toString().padStart(2,"0")}:${mins.toString().padStart(2,"0")}`
return msg;

[Edit] Corrected code to pick up from msg.payload.Start

@Tilerdon does my simpler solution work for you?

Anyone else, can you confirm whether it works ok with a timezone other than uk?

I am pretty sure it will not work if the browser and server timezones are different, and I don't think there is any way to make it work, unless someone can think of anything. The problem is that it is necessary to know the browser timezone.

It would have been better if the node sent the time as received from the browser, including the the TZ information, but there is not much that can be done about that now. I can't think of a way of fixing it and keeping it backwards compatible, other than having a new option to change the format.

@Colin the code works fine with a modification to the first line in order to work with @Tilerdon's flow - msg.payload.time should be msg.payload.Start

Screen Shot 2022-11-29 at 6.27.07 AM

Oh yes, I was testing with a reduced example.
I will correct my post.
Thanks.

1 Like

Yes @Colin that works fine thank you. I agree that it does look simpler than the other code that I picked up. Not quite sure about the use of $ however but that is a matter for me to resolve at some other time.

Thank you all for your help and the interesting issues raised by it.

msg.payload = `${hours.toString().padStart(2,"0")}:${mins.toString().padStart(2,"0")}`

That is just using string template literals. The above is exactly the same as

msg.payload = hours.toString().padStart(2,"0") + ":" + mins.toString().padStart(2,"0")

but is arguably easier to code and to understand. It doesn't make much difference in this case, but if you are trying to build a string with quotes and double quotes in it then the traditional method can get horribly complex.

1 Like