Issue converting Luxon date to a selected Time Zone from user cookie

Viewed 288

I am working on a web application that needs stores a start and finish value for a work shift. The application has a timezone selection component which updates any date/time values in UI to match the time in a given timezone/location by changing a timezone cookie. Values are stored in a database as UTC values and they are passed through a controller to convert them between the DB and UI.

I am working on a page that has an exception where the start and finish times are changeable/editable by the user after saving. The page will get these values from UI Date Boxes. The values can convert to UTC on saving values with no issue with use of Luxon, however, a user can navigate back to the given page to edit saved values if changes are needed. When this happens, the saved values are loaded into these DevExpress/DevExtreme date boxes but they are not displayed as expected.

The values come from an odata response and is read as response.value[0].Start. When getting the value, an offset is applied based on the users cookie location, so in my case (Europe/London timezone) the response would be 2022-05-24T01:00:00+01:00.

I can convert this to UTC using DateTime.fromISO(response.value[0].Start).toUTC() to give me a value of 2022-05-24T00:00:00.000Z which is expected.

However I am running into converting this value to the desired value for a selected timezone. I try to do so with the following:

var DateTime = luxon.DateTime;
//selectedTimeZone found from cookie.

// -- logic --

if (response.value[0].Start != null) {
    var dateBox = $("#ShiftBeginning").dxDateBox('instance');   
    var converted = DateTime.fromISO(response.value[0].Start).toUTC().setZone(selectedTimeZone, {keepLocalTime: true}); 
    dateBox.option({ value: converted});
}

//Example selectedTimeZone: Asia/Tokyo
//converted.toString() value: 2022-05-24T00:00:00.000+09:00 (Tokyo time zone)
//Displayed UI Time value:  16:00
//Displayed UI Time value with {keepLocalTime: false}: 01:00

It appears as if the value of converted is having the offset applied twice, with an hour then taken off of the time to represent UTC.

I have tried changing parsing this value to different formats, tested different timezones, using standard JavaScript Date object etc. and I am beginning to run out of ideas.

Any help is appreciated to help solve this.

1 Answers

It's being "converted" twice because the time picker doesn't respect the zone in your cookie, because it doesn't know about it. Remember that the time is the time; the zone and how the time is represented in that zone are more like metadata. So it's expressing the time in user's system zone, and the local time it displays is off from what you expect by the difference between where they are and Tokyo's local time.

What you want to do is:

  1. find the local time in Tokyo for your time. This is probably just DateTime.fromISO(s).setZone(selectedZone). You don't want keepLocalTime because your time is correct
  2. change to the user's system zone, but keeping the time constant, which is just converted.setZone("system", { keepLocalTime: true }). We do this because we want a local time that is, technically, wrong; it's what local time matches the right Tokyo time. This is more-or-less the purpose of keepLocalTime: to trick zone-unaware components into showing a local time in another zone.
  3. It's a little odd that you're passing the Luxon DateTime directly to the time picker. I guess it's calling valueOf() on the value you pass in. But you'd probably want to do that yourself to be confident you're telling it the right thing.

So all together:

var converted = DateTime
      .fromISO(response.value[0].Start)
      .setZone(selectedTimeZone);
      .setZone("system", { keepLocalTime: true });

dateBox.option({ value: converted.valueOf() });
Related