Letting users choose timezone for scheduling system: Problem with returning today on server

Viewed 209

I'm having trouble with the scheduling system I am creating in node (client and server API). My server is in UTC.

As I wanted my timezone to be consistent wherever the user was based, I suggested a timezone to the user based on their business address provided. The aim was for the user to be able to view their scheduling details from anywhere around the world, and still see the same dates. eg. User business is based in the UK, and they schedule a booking for 8pm. Then user travels to Asia for a holiday, logs into the system, and still sees the booking specified as 8pm, and can use the calendar to schedule more bookings, which can then be viewed back in the UK at the Date specified when abroad.

This had been working well up until now. I am saving the user timezone against the user on signup. I am storing the dates in the postgres database without timezone. When retrieving from the database, I am using

date = moment(fetcheddate).tz(usertimezone, true);

When I am working at server/client boundaries (and am expecting a timezone), I am using:

date = moment(receiveddate).tz(usertimezone);

This ensures that all dates are consistently in the business timezone whenever they are being used, with the express aim of all dates consistently reading as a moment object with the time always set to 00:00:00.

On the server, my business logic makes a lot of use of Moment add/subtract; isSame/isBefore/isAfter to generate new dates internal to the workings of this scheduling system.

Now the problem. Occasionally, I need to know what the current day is. eg. On the server, I alter a blockbooking by enddating the currently saved block booking, setting to "yesterday", and starting a new blockbooking from "today". .

Looking at the "alter block booking" scenario in more detail: on the server I generate "today" by calling moment, and converting into the business timezone, using moment startOf('day') to remove time info.

today = moment().tz(usertimezone).startOf('day');

I then set startdate on my new blockbooking object equal to this today value.

Now, if the user is in the same timezone as the business timezone, then this works perfectly. However, if they are working from abroad at the time in a different timezone, then I get the problem that my startday is a day out.

For instance, my current blockbooking saved info may have a start date of "2021-02-06 00:00:00". I choose to alter this blockbooking on the same day, 6th Feb, when abroad. I expect my new startdate to also equal the 6th. However, using today = moment().tz(usertimezone).startOf('day') results in me getting 5th of Feb as my new startdate, which is a day out.

I can't rely on just using moment() to get the correct date, as the server is in utc. The only solution I can think of is to pass up the browser timezone from the client using

moment.tz.guess(); 

But I'm not sure I can completely trust this call for such integral functionality, as it seems that there may be a number of bugs. eg. Return timezone name with Moment's guess().

I'm sure there must be a solution for this that I'm not thinking of. Perhaps my choice of using the business timezone to sync datetimes is a problem. I think that passing dates without timezones at server boundaries would work for the majority of functionality, and might simplify things, although I am not sure. But I think I still hit the same problem of generating the "today" date on the UTC server.

Does anyone have any ideas around this? What have I missed?

UPDATE: Upon request, my main question is how do I get the date value of "today" in server such that it is equal to "today" in browser. This "today" date in server must then be compared against dates that are set to the user's business timezone. Or if you have an alternative implementation that circumvents this issue then that is acceptable too

1 Answers

How to design when users are from different timezones?

  1. Store datetime in UTC in your database.
  2. After users signup, when they login to your web application, ask them to choose a timezone. This can be part of Profile page of their user account. Store this timezone in database for each user.
  3. Communicate in UTC timezone with other services, e.g. web application.

Example.1:

User chose UTC-8 as his timezone through profile. And, He is making a booking for 03-Feb-2021 20:00:00 (his timezone, obviously). Now, web application would send / communicate through API as 04-Feb-2021 04:00:00, and, very simple, backend would store it as it is - 04-Feb-2021 04:00:00.

Now, lets say user logs out and logs back in and check his calendar, now again, web application would make HTTP API call to fetch that booking and backend would respond with booking date as 04-Feb-2021 04:00:00.

Now, it is web application's job to find out (from profile data, e.g. stored in browser localstorage or with session storage) the user's chosen timezone which is UTC-8 and do the conversion and show the user back booking as - 03-Feb-2021 20:00:00


Example.2:

User made a booking for a webinar (let's go with this example) which will start at 15-Feb-2021 14:00:00 in UTC+8. Booking is done using a web application, so the web app sends the event start time as 15-Feb-2021 06:00:00 which gets stored in database.

Now the user travels to a new timezone, let's say, UTC+10 and updates his timezone using profile section which gets saved in database as well.

After updating his timezone, he checks his schedule and the web application (after conversion) tells him the event will start at 15-Feb-2021 16:00:00, and that is correct for the user.

Because, in real world, the webinar will start at - 15-Feb-2021 06:00:00 UTC == 15-Feb-2021 14:00:00 UTC+8 == 15-Feb-2021 16:00:00 UTC+10

So, no one is going to miss the webinar, people living in UTC, people living in UTC+8 and those living in UTC+10 are going to attend at the same time.


Case 3, Local Events

While creating an event, let the user choose / mark an event as local event, and when they do it, store event details, datetime in UTC and event's timezone id in database against each event record in table.

To display this event in web app, you need to send the event datetime in UTC and event's timezone details to frontend. And, front end can always show the event in event's timezone no matter if user travels to different timezone in future.

Related