Search code examples
c#datetimeutcnodatimeiana

How Do I Convert IANA zone + datetime to UTC + Offset using NodaTime


I have local time in string format: "yyyy-MM-dd HH:mm:ss" and an IANA Time Zone for that time (e.g. "Europe/London").

How do I convert that in C#, maybe using NodaTime, to a UTC+TimeZone Offset string

e.g. "yyyy-MM-dd HH:mm:ss+01:00" ?

I don't even know where to start!

This is as far as I get (I am afraid I'm new to C sharp): I understand I need to convert it to an instant, but just can't get to grips with the library.

string dateTime = "2014-12-31 12:30:00";
string IANA = "Europe/London";
Instant instDateTime = NodaTime.Instant.FromDateTimeUtc(Convert.ToDateTime(dateTime));
string outputUTC = string.Format("yyyy-MM-dd HH:mm:ssZ", instDateTime);

Thanks to Matt (see answer below), I now have the functions I needed (Note that in the end what I needed was UTC and not date time + offset):

What is a little worrying is that is says that Europe/Moscow is UTC+04:00, whereas it is actually UTC+03:00 since 26 October 2014.

    static void Main(string[] args)
    {
        string dateTime = "2014-12-31T12:30:00";
        string timeZone = "Europe/Moscow";

        Console.WriteLine(timeZone + " Local time '" + dateTime + "' to Zulu time");
        Console.WriteLine(ConvertIANALocalTimeToZulu(timeZone, dateTime));
        Console.WriteLine();
        Console.WriteLine("Zulu time '" + dateTime + "' to " + timeZone + " local time");
        Console.WriteLine(ConvertZuluTimeToIANALocalTime(timeZone, dateTime));

        Console.ReadLine();
    }

    static string ConvertIANALocalTimeToZulu(string timeZoneIANA, string localDateTime)
    {
        var pattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-ddTHH:mm:ss");
        LocalDateTime ldt = pattern.Parse(localDateTime).Value;
        ZonedDateTime zdt = ldt.InZoneLeniently(DateTimeZoneProviders.Tzdb[timeZoneIANA]);
        Instant instant = zdt.ToInstant();
        ZonedDateTime zulu = instant.InUtc();
        ////string output = zulu.ToString("yyyy-MM-dd HH:mm:sso<m>", CultureInfo.InvariantCulture);
        string output = zulu.ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture);

        return output;
    }

    static string ConvertZuluTimeToIANALocalTime(string timeZoneIANA, string zuluDateTime)
    {
        var pattern = InstantPattern.CreateWithInvariantCulture("yyyy-MM-ddTHH:mm:ss");
        Instant instant = pattern.Parse(zuluDateTime).Value;
        ZonedDateTime zdt = instant.InZone(DateTimeZoneProviders.Tzdb[timeZoneIANA]);
        ////string output = zdt.ToString("yyyy-MM-dd HH:mm:sso<m>", CultureInfo.InvariantCulture);
        string output = zdt.ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture);

        return output;
    }

Solution

  • It's unclear from your question if you meant that the original value was in UTC or in local time.

    If it's in UTC, then do the following:

    string dateTime = "2014-12-31 12:30:00";
    string timeZone = "Europe/London";
    
    var pattern = InstantPattern.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss");
    Instant instant = pattern.Parse(dateTime).Value;
    ZonedDateTime zdt = instant.InZone(DateTimeZoneProviders.Tzdb[timeZone]);
    string output = zdt.ToString("yyyy-MM-dd HH:mm:sso<m>", CultureInfo.InvariantCulture);
    

    If it's in local time, then do this instead:

    string dateTime = "2014-12-31 12:30:00";
    string timeZone = "Europe/London";
    
    var pattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss");
    LocalDateTime ldt = pattern.Parse(dateTime).Value;
    ZonedDateTime zdt = ldt.InZoneLeniently(DateTimeZoneProviders.Tzdb[timeZone]);
    string output = zdt.ToString("yyyy-MM-dd HH:mm:sso<m>", CultureInfo.InvariantCulture);
    

    Also - you should note that in December, London is on GMT (UTC+00:00) - so the output of either function will be "2014-12-31 12:30:00+00:00" for the values you provided.