Search code examples
c#.nettimezoneutc

Get time zone with UTC conversion


I have the system date in BST . I want to convert it to UTC. So did the below:

string utcDate= TimeZoneInfo.ConvertTimeToUtc(dt).ToString("dd/MM/yyyy HH:mm:ss");

What I want is to get the zone along with the Date in UTC. Pls consider the daylight savings.

Example: 2019-07-08T23:59:00+01:00.


Solution

  • A few things:

    • The string format you gave the example of, 2019-07-08T23:59:00+01:00 is part of the ISO 8601 specification. To be precise, it is the "complete date and time of day representation" of the "ISO 8601 Extended Format". It also the format defined by RFC 3339.

    • In this format, the date and time portion represent the local time, as denoted by the time zone offset portion. In other words, the values are not in UTC, but already adjusted. In your example, 2019-07-08T23:59:00 is the local time and UTC+01:00 is in effect at that time. The corresponding UTC time would thus be an hour earlier, 2019-07-08T22:59:00Z.

    • You seem to be asking for the date in UTC but with an offset that includes daylight saving time. That is impossible, as UTC does not observe daylight saving time. The offset from UTC is always zero. You can read more about UTC here.

    • The offset of UTC itself is denoted with Z, but can also be represented with +00:00, which can be thought of as "zero offset from UTC". In other words, if you are referring to UTC time use the Z, and if you are referring to a local time that is aligned to UTC (such as GMT in London in the winter, or Iceland, etc.) use +00:00.

    • In your question, you say you want the system time in UTC with the offset. I will assume by "system time" you mean the current time of the clock on the system. That is provided by DateTime.UtcNow or DateTimeOffset.UtcNow. These return either a DateTime or DateTimeOffset structure - not a string. Since you wanted a string in a specific format, then you should first ask for the current time, and then format it as a string with ToString:

      using System.Globalization;
      

      ...

      string a = DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture);
      // output example: "2019-07-08T22:59:00Z"
      
      string b = DateTimeOffset.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:sszzz", CultureInfo.InvariantCulture);
      // output example: "2019-07-08T22:59:00+00:00"
      
    • If what you actually wanted was the local time, such that the offset would be +00:00 in the winter and +01:00 in the summer (in the UK), then use Now instead of UtcNow. This gives the local time in the time zone of the computer where the code is running.

      string c = DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture);
      // output example: "2019-07-08T23:59:00+01:00"
      
      string d = DateTimeOffset.Now.ToString("yyyy-MM-dd'T'HH:mm:sszzz", CultureInfo.InvariantCulture);
      // output example: "2019-07-08T23:59:00+01:00"
      
    • If you actually wanted the time in the UK regardless of what the time zone of the local computer was on, then you'd have to first get the UTC time and then convert it to UK time before creating the string.

      TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
      string e = TimeZoneInfo.ConvertTime(DateTime.UtcNow, tzi).ToString("yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture);
      // output example: "2019-07-08T23:59:00"
      
      string f = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzi).ToString("yyyy-MM-dd'T'HH:mm:sszzz", CultureInfo.InvariantCulture);
      // output example: "2019-07-08T23:59:00+01:00"
      

      In example e, note that a DateTime can't store an arbitrary offset as the result of time zone conversion, and thus you get DateTimeKind.Unspecified assigned to the Kind property, which results in no offset being in the string representation. Thus most of the time you should use a DateTimeOffset (example f) instead.

      Also, note the time zone ID of "GMT Standard Time" is the correct ID to use for the UK on Windows platforms. It correctly switches between GMT and BST when appropriate. If you are running .NET Core on non-Windows platforms (Linux, OSX, etc.), then you should use "Europe/London" instead. Or if you are wanting to write code that is platform-neutral then you can use my TimeZoneConverter library, which allows you to provide either form and run on any platform.

    • In your code example, you didn't call any of the "now" functions, but gave a dt variable. Assuming this is a DateTime, the result of calling TimeZoneInfo.ConvertTimeToUtc will depend on the Kind property of that variable. If it's DateTimeKind.Utc, then no conversion is performed. If it's DateTimeKind.Local or DateTimeKind.Unspecified, then the value is converted from the computer's local time zone to UTC.

    • Lastly, keep in mind that when talking to an international audience, time zone abbreviations can be ambiguous. I could deduce by "BST" that you meant British Summer Time, but only because you showed a +01:00 offset in your question. "BST" can also stand for "Bangladesh Standard Time" (+06:00), or "Bougainville Standard Time" (+11:00).