0

I am building a system that allows a user to specify his/her working hours. This is stored in the database as:

  • DayOfWeek: Monday
  • StartTime: 08:00
  • EndTime: 17:00

This information is relative to the User A, so based on his time zone. Which the user selects in his/her profile e.g. (UTC+00:00) Dublin, Edinburgh, Lisbon, London

What am I trying to Achieve?

  1. User B currently makes a call to a .NET Web API with a Date e.g. 01 Jan 2019.
  2. I need the API to return User A working hours but in User B time zone.
  3. User B can then book that time with User A by making a second call to the API. In this case the booking is stored in UTC date format.

What I Need?

Can someone please provide a suitable solution for this as both User A and User B can have different Time Zones?

DevSolo
  • 3
  • 2
  • I'd suggest storing the time information in UTC format, and then formatting it for the user viewing the information with that users timezone information. – Erik Funkenbusch Oct 30 '18 at 12:34
  • @ErikFunkenbusch - no. This is a scenario where storing as UTC is not the right thing to do. Otherwise, changes in local time of user A will not correct be reflected. Consider daylight saving time, and changes to standard time, both of which are at the mercy of local governments, and do indeed change. – Matt Johnson-Pint Oct 30 '18 at 14:41
  • @SoleDev - it sounds like you have all the information you need as to general approach. Are you looking for guidance on strategy? Or are you wanting help with your code? You can use `TimeZoneInfo` or `NodaTime` to solve this, but it would be good if you made an initial attempt yourself. If you get stuck, post the relevant code here by editing your question, and we can help from there. Also many of these types of things have been asked already. Search the [tag:timezone] tag. Thanks. – Matt Johnson-Pint Oct 30 '18 at 14:54
  • I’m looking for a best of breed approach, I am already storing each users TimeZone and the users availability in UTC format. – DevSolo Oct 30 '18 at 18:27
  • ... so what have you tried? What worked? What didn't? What parts specifically are you asking for help with? Please read from the help center: [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) and [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). Presently, you've listed several requirements, and seem to be asking for a complete solution to be created for you - but that's not what StackOverflow is generally about. Either ask a reduced, direct question, or show the code *you've* written for help to solve the larger problem. – Matt Johnson-Pint Oct 30 '18 at 20:11
  • @MattJohnson - No, you are incorrect. Storing time as UTC is the correct method. There are plenty of methods to convert UTC to local time (including timezone information). In fact, storing time as UTC is the only reliable way you can do math between two times, since timezones and DST are not involved. UTC is the one true time. LocalTime is just an interpretation of it. – Erik Funkenbusch Oct 31 '18 at 01:38
  • Sorry, but I'll have to disagree. The advice "always use UTC" is not entirely correct. It makes perfect sense for timestamping, but it not usually for scheduling. Please read [this blog post](http://www.creativedeletion.com/2015/03/19/persisting_future_datetimes.html) and [this S.O. answer](https://stackoverflow.com/a/19627330/634824). – Matt Johnson-Pint Oct 31 '18 at 02:51
  • Consider the schedule given in the example. The start time is 08:00 every day, and the user is in London. It doesn't matter if that day is when London is in its standard time (GMT = UTC+0) or in its summer time (BST = UTC+1). The schedule itself is in *London* time. Otherwise, some dates will convert different times to UTC than others. Yes - UTC is the correct approach as the intermediate, but not for the *storage* of the schedule. In other word, on a given day, convert from the schedule local time on that day, to UTC, then from UTC to local time in the target user's time zone. – Matt Johnson-Pint Oct 31 '18 at 02:51
  • Also, whole dates (such as birthdays) are another example where converting to UTC is not correct. – Matt Johnson-Pint Oct 31 '18 at 02:52
  • @MattJohnson the current solution I have is that I store User A’s working hours as start and end times for each day of the week. I also store the users TimeZone. Currently the API will return the Working Times as a JSON Payload with the workers TimeZone. I then display this data for User B and perform the adjustment with User B TimeZone offset using client side JS. When User B decides to book, the request back to the API is done using User A TimeZone setting and then that date time value is converted and stored in UTC format. – DevSolo Oct 31 '18 at 04:45

2 Answers2

0

You can take a look at NodaTime, probably best timezone-related library for .NET The same is achieved using built-in .Net functionality, but there are some tricky rare issues with it, so it is more reliable for use NodaTime.

dlxeon
  • 1,932
  • 1
  • 11
  • 14
0

In your comments under the question, you said:

the current solution I have is that I store User A’s working hours as start and end times for each day of the week. I also store the users TimeZone. Currently the API will return the Working Times as a JSON Payload with the workers TimeZone. I then display this data for User B and perform the adjustment with User B TimeZone offset using client side JS. When User B decides to book, the request back to the API is done using User A TimeZone setting and then that date time value is converted and stored in UTC format.

This is mostly good, except when you say that you perform the adjustment using User B's time zone offset.

The problem is that many time zones go through different offsets depending on what date and time you are talking about. For example, if in client-side JS you do something like new Date().getTimezoneOffset(), you are getting the user's current offset. It is not necessarily the same offset that should apply for the date in question. More on this under the heading "Time Zone != Offset" in the timezone tag wiki.

Also, you go on to say that the request back to the API is done in user A's time zone (which is fine), but that you then convert and store the time as UTC. Be careful there - you need to retain the intended appointment time. It's fine to know what the UTC time of a specific event might be, but indeed this can change too.

As an example, consider the latest time zone changes that occurred in Morocco. They were planning to end daylight saving time on October 28th 2018, switching the clocks back from UTC+1 to UTC+0. However, on October 26th 2018, with just two days warning, the government announced that they would stay on UTC+1 permanently and abolish daylight saving time. These sorts of short-notice changes are highly problematic, and has happened around the world many times before. I wrote a blog post about them a couple of years back, which is still highly applicable today.

So, if user A was in Morocco, and you stored an appointment for sometime after the change in UTC, well then since the change didn't happen their appointment would now appear an hour shifted on their local calendar.

In such events, if you had retained the intended local time of the event, then you could also have a process to recompute the UTC time based on what current time zone data you have installed. Short notice changes are super hard, but if there had been say a few months notice, then you'd have time to apply updates and correct the times of the events programmatically. If you only stored the UTC time, then you'd not have that ability.

Another way to think about this is that while UTC always keeps ticking forward consistently (except in some cases around leap seconds), human beings don't think in such terms. If I say that I want to meet you at 10 am in some place, the meeting is aligned to the local time of that place - no matter what changes between the time in that place and UTC occur.

Conversely, scheduling a meeting based on UTC is taking it on blind faith that no changes beyond what are currently predicted will happen. Since we aren't able to peer into the future, we really shouldn't be making such assumptions.

(And again, if you'd like help with code, please show what code you've tried in your question. Generally in .NET, one uses the TimeZoneInfo class for this. Here's an overview on how to use it.)

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Thanks for the detailed reply Matt, reallyu appreciate it! – DevSolo Nov 01 '18 at 12:28
  • Just so I am clear, when I mean I adjust the dates, this is done using the users timezone relative to that date, so if the user is viewing a future week which is several months from now, it will use the timezone + any daylight saving currently understood for that future week. – DevSolo Nov 01 '18 at 12:33