E4est
E4est

Reputation: 95

Pass timezone from Angular app to ASP.NET Core 3.1 backend

I am trying to get appointments that are saved with UTC times filtered by e.g. the date. The problem is an appointment can be saved for UTC June 1st 10:00 PM, but when the user is located in Germany, that would be June 2nd 12:00 AM for that user's local time. When the user requests all appointments for June 1st that appointment should not appear, but when June 2nd is requested, it should.

As long as the backend doesn't know which timezone to apply, it will behave the other way around.

I am aware of ToLocalTime() in the backend, but as for my understanding that will only behave correctly as long as the client is in the same timezone as the server.

One might say, that I could use getTimezoneOffset() on the client side and pass it to the backend in some way. But that won't work, because of daylight savings. UTC December 1st 10:00 PM would result in a German local time of December 1st 11:00 PM, so applying the current timezone offset doesn't help.

I figured out, that most browsers will support Intl.DateTimeFormat().resolvedOptions().timeZone to get the timezone as a text. But passing that one to the backend didn't help either, because when I check the list of supported timezones returned by TimeZoneInfo.GetSystemTimeZones() in the backend, I can't find the same string as the browser provides. (browser returns 'Europe/Berlin', Id in backend is 'W. Europe Standard Time', other strings are even localized)

I know that I'm exhausted a bit, because working with dates and times was a reoccuring theme for me today, but am I missing out on something obvious? What can I do to make the backend aware of the relevant timezone? And how would I get the DateTime for that specific timezone?

Upvotes: 2

Views: 1335

Answers (1)

Matt Johnson-Pint
Matt Johnson-Pint

Reputation: 241475

You're on the right track with regard to time zone conversion:

  • In the browser, get an IANA time zone identifier:

    const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone;
    
  • Pass that to the server

  • In .NET, there are three different approaches to use the IANA time zone identifier:

    • You can use my TimeZoneConverter library:

      TimeZoneInfo tz = TZConvert.GetTimeZoneInfo(tzid);
      
    • You can use the Noda Time library:

      DateTimeZone tz = DateTimeZoneProviders.Tzdb[tzid];
      
    • Without a library, you can use an IANA time zone identifier on Linux. (This will also soon work on Windows starting with .NET 6.)

      TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(tzid);
      
  • You can then use the conversion methods on either the TimeZoneInfo or DateTimeZone object to convert between UTC and the specific time zone.

However - You might want to rethink your approach to storing appointment times. You said:

... an appointment can be saved for UTC June 1st 10:00 PM, but when the user is located in Germany, that would be June 2nd 12:00 AM for that user's local time.

In most cases, future appointments should be stored with respect to the date and time of the time zone associated with the appointment's location, along with the identifier of that time zone. In other words, don't store the above appointment in UTC. Instead, store "June 2, 12:00 AM, Europe/Berlin". When needed, convert from the local time to UTC or another time zone.

Some like to say "always use UTC", but that advice is incorrect with regard to future events. UTC is best for past/present events, such as timestamping sales transactions or entries in log files.

Upvotes: 1

Related Questions