Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting time between different time zones

I am building a windows store clock app to show the current time of the user and also for different cities around the world.

Initially, I had planned on doing this completely using time zone web services from Google etc., but after looking at the number of requests allowed in free accounts and the cost involved in getting a paid account, I felt it was better to find an alternate solution without having to mortgage the house.

Searching around, I found the excellent NodaTime library by John Skeet and team. After digging through the documentation and here on stackoverflow, my head is still buzzing with all the date time and timezone related terminology and conversion methods. Anyway, I thought I could do this with 2 options:

Option 1: Using DateTime.Now to get the current system time and then getting time for other zones using nodatime like this (based on code provided by Matt Johnson in reply to another question on SO):

DateTimeZone homeZone = DateTimeZoneProviders.Tzdb["Asia/Colombo"];
LocalDateTime homeTime = LocalDateTime.FromDateTime(DateTime.Now);
ZonedDateTime homeTimeInZone = homeTime.InZoneStrictly(homeZone);
TbTime1.Text = "Home time is: " + homeTimeInZone.ToDateTimeOffset();

DateTimeZone timeZone1 = DateTimeZoneProviders.Tzdb["Australia/Perth"];
ZonedDateTime timeZone1Time = homeTimeInZone.WithZone(timeZone1);
TbTime2.Text = "Timezone 1 time is: " + timeZone1Time.ToDateTimeOffset();

Option 2: After looking further, I found this solution and felt it would also work nicely like this:

public ZonedDateTime GetTimeInTimeZone(string timeZone)
{
    // Timezone is olson timezone e.g. "Asia/Colombo"
    Instant now = SystemClock.Instance.Now;
    var zone = DateTimeZoneProviders.Tzdb[timeZone];
    ZonedDateTime zonedDateTime = now.InZone(zone);
    return zonedDateTime;
 }

Now let me try to get to the question: In both options above, there is a dependency on either DateTime.Now or SystemClock.Instance.Now to first identify the user's system time and THEN convert it to the required timezone's city time. But what happens if the user's system is not set to the correct time? I believe (correct me if wrong) DateTime.Now and SystemClock.Instance.Now are both using the system clock to get the current time? Assuming that the system time is not set correctly, then any timezone conversion will simply show the wrong time for other cities due to our dependency on the user's system time.

In such cases, how do I establish the user's current time without relying on their system clock? Should I revert to using a web service to get the user's current time zone using lat/long or is there a better option using NodaTime etc that can work offline? Thanks.

like image 766
Girish Avatar asked Dec 01 '25 14:12

Girish


1 Answers

A couple of points:

  • Avoid using DateTime.Now

    • It's already translated to the local time zone, so during DST fall-back transitions the result can be ambiguous.
    • If you need to get an exact unambiguous moment in time without using Noda Time, then use DateTime.UtcNow.
    • You could also use DateTimeOffset.UtcNow, or DateTimeOffset.Now. When the offset is included, there is no ambiguity.
    • See also The Case Against DateTime.Now on my blog.

  • In Noda Time, realize that SystemClock.Instance is an implementation of the IClock interface. Whenever possible, you should code against the interface, such that you can replace the implementation in your unit tests if desired. Though in the simplest of examples, there's nothing wrong with calling SystemClock.Instance.Now, it just isn't as testable.

  • As far as which time zone input to use, that is entirely based on your application requirements.

    • If you can depend on the system to be set to the correct zone, you can retrieve it with

      DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
      
    • If you can't depend on the system time zone to be set correctly, you might consider some other source of input.

    • You mentioned GPS coordinates. If you have that, perhaps from a mobile device, there are solutions for resolving it to a time zone. See here for some options. Noda Time can't help you in this regard.

    • You might also consider asking the user of your app to pick a time zone from either a drop-down list or a map. There are some map-based time zone pickers for HTML/JS here and here. (I am unsure if they will work in a WinJS based Windows Store App or not, and I don't know of any XAML based solutions off hand.)

  • If the actual time of their clock is set wrong, there's not a lot you can do, other than try to reach out to another server to retrieve a time stamp. In most cases, you should rely on the operating system to already be synchronized with a time server.

    • If you do require synchronization with an external service, that can be challenging. You need something that implements NTP properly, including measuring and compensating for transmission delay. That's not easy, and probably requires an external library. I don't know of one off-hand to recommend.

    • Reaching out to a web service and returning the current time isn't necessarily going to be as accurate as you might think, as that does not compensate for the time it takes for the server to transmit that response to you.

    • If you are running on a device with a GPS receiver, then it is technically possible that it can provide an accurate time stamp received from the GPS signal. Whether or not that is retrievable and usable via the Windows Store API, I am not sure. I checked a few references on MSDN but came up empty.

  • Regarding the two code samples you provided, they're doing slightly different things, but go with option 2. It's much cleaner, and is pure Noda Time.

like image 129
Matt Johnson-Pint Avatar answered Dec 04 '25 20:12

Matt Johnson-Pint



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!