2

I am trying to design the following timezone solution using Noda Time:

A user would use a mobile app or web app to log in to the system. At the time of login a web API would be called with offset from UTC (let's say x minutes) as a parameter.

Now if the offset (x minutes) is different from offset (and timezone) saved in database, then the user would be shown a list of timezones which are x minutes away from UTC, so that they can select one out of them. The selected timezone and corresponding offset (x minutes) would then be saved in the database as the user's latest timezone.

How do I get a list of timezones which are x minutes away from UTC using Noda Time?

For example, if the user is +330 minutes away from UTC, then the user would get this prompt:

We have found that you're 5 hrs 30 minutes ahead of GMT. Please select your current timezone: "Asia/Colombo", "Asia/Kolkata"

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dipendu Paul
  • 2,685
  • 1
  • 23
  • 20
  • I get what you are trying to do, but if you can work out how far from UTC the user is, can't you get their actual position, and therefore know what their current timezone is? – Neil Sep 01 '18 at 07:50
  • @Neil, only common thing between different clients(mobile or web) is to unambiguously determine offset from UTC. There is no common identifier of a timezone across all platforms. – Dipendu Paul Sep 01 '18 at 07:59
  • Web pages and mobile can get current location (usually after a prompt) and you can then instantly get the correct timezone, which is probably easier for the user than providing a list of maybe 10 different timezones (and the user selecting the wrong one).. – Neil Sep 01 '18 at 08:03
  • Your solution makes sense to me, probably it would be easier for user to confirm current location. For implementing this solution I might need a mapping between location to timezone. Can you please explain the solution that you're suggesting? – Dipendu Paul Sep 01 '18 at 08:20
  • 1
    https://stackoverflow.com/questions/6939685/get-client-time-zone-from-browser – Neil Sep 01 '18 at 08:23
  • Thanks! this solution would definitely work for web. I needn't have to prompt user for choosing location, I can just determine her timezone and save it in DB. But can the same solution be extended on mobile end(iOS or Android)? – Dipendu Paul Sep 01 '18 at 08:30
  • 1
    Android: https://developer.android.com/reference/java/util/TimeZone iOS: https://developer.apple.com/documentation/foundation/timezone – Neil Sep 01 '18 at 08:33
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/179231/discussion-between-dipendu-paul-and-neil). – Dipendu Paul Sep 01 '18 at 08:48

2 Answers2

3

You can do something like this:

TimeZoneInfo.GetSystemTimeZones()
    .Where(x => x.GetUtcOffset(DateTime.Now).TotalMinutes == 330)

And now you have a collection of the time zones! You can replace DateTime.Now with some other date or a DateTimeOffset depending on your situation.

In Noda Time, you can do this:

using NodaTime;
using NodaTime.TimeZones;

TzdbDateTimeZoneSource.Default.GetIds()
    .Select(x => TzdbDateTimeZoneSource.Default.ForId(x))
    .Where(x => 
        x.GetUtcOffset(SystemClock.Instance.GetCurrentInstant()).ToTimeSpan().TotalMinutes == 330)
Sweeper
  • 213,210
  • 22
  • 193
  • 313
2

A slightly alternative approach to Sweeper's code, using a target offset instead of converting each offset to a TimeSpan, using a single computation of "now" (for consistent results) and using the IDateTimeZoneProvider.GetAllZones extension method.

using System;
using System.Linq;
using NodaTime;
using NodaTime.Extensions;

class Test
{
    static void Main()
    {
        // No FromMinutes method for some reason...
        var target = Offset.FromSeconds(330 * 60);
        var now = SystemClock.Instance.GetCurrentInstant();
        var zones = DateTimeZoneProviders.Tzdb.GetAllZones()
            .Where(zone => zone.GetUtcOffset(now) == target);
        foreach (var zone in zones)
        {
            Console.WriteLine(zone.Id);
        }
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194