Search code examples
nodatime

What is equivalent of TimeZoneInfo.ConvertTime in NodaTime?


I want to use the NodaTime library to convert the date from one timezone to another like this.

string fromSystemTimeZoneId = "GMT Standard Time";
string toSystemTimeZoneId = "Central Standard Time";
TimeZoneInfo fromTimeZone = TimeZoneInfo.FindSystemTimeZoneById(fromSystemTimeZoneId);
TimeZoneInfo toTimeZone = TimeZoneInfo.FindSystemTimeZoneById(toSystemTimeZoneId);
var convertedTime = TimeZoneInfo.ConvertTime(inputDateTime, fromTimeZone, toTimeZone);

The above code works perfectly fine for me, But now I want to use IANA standard time zone (like Europe/London and America/Chicago) in place of windows OS-provided time zone ids.

I am using .net 4.7.2 and cannot upgrade the framework due to some limitations.

I have gone through this answer, But I am looking for simple few lines of code nothing complicated.


Solution

  • But I am looking for simple few lines of code nothing complicated.

    But you're trying to do something complicated. Noda Time makes everything explicit, which means it's clear exactly what's going on - at the cost of being a little more verbose.

    DateTime has no concept of a time zone itself (other than for the special cases where the Kind is Utc or Local). So TimeZoneInfo.ConvertTime has to:

    • Consider what instant in time is represented by inputDateTime in fromTimeZone
    • Work out what that instant in time looks like in outputDateTime

    In Noda Time, those are are two separate operations, if you want to start and end with a LocalDateTime:

    LocalDateTime inputDateTime = ...;
    DateTimeZone fromTimeZone = ...;
    DateTimeZone toTimeZone = ...;
    
    // There are options for how this conversion is performed, as noted in other questions
    ZonedDateTime inputDateTimeInFromTimeZone = inputDateTime.InZoneLeniently(fromTimeZone);
    // This conversion is always unambiguous, because ZonedDateTime unambiguously
    // refers to a single instant in time
    ZonedDateTime inputDateTimeInToTimeZone = inputDateTimeInFromTimeZone.WithZone(toTimeZone);
    
    LocalDateTime localPart = inputDateTimeInToTimeZone.LocalDateTime;
    

    So that's basically the equivalent conversion - but you need to be explicit about how you want to handle skipped/ambiguous inputs. If you want everything in your app to use the same conversion, you can wrap that in a method that looks just like TimeZoneInfo.ConvertTime. But why not just keep things in a ZonedDateTime instead of LocalDateTime to start with? Then you don't get into the ambiguous position - other than potentially when converting user input (which is entirely separate from converting from one time zone to another).