Search code examples
c#datetimetimezonedatetimeoffset

Error converting from datetime UTC to datetimeoffset when kind is Utc


There is an error converting a DateTime in UTC to a DateTimeOffset type when the kind is Utc.

The origDateTime comes from webservice so I don't have control of the content or format.

In most of the cases it comes with Kind=Unspecified (even tough the time is in Utc) and then it's working, but in rare cases the Kind=Utc and then the conversion to DateTimeOffset throws an exception:

"The UTC Offset for Utc DateTime instances must be 0. Parameter name: offset"

How should I solve this?

try {

    //causees error !!!!
    DateTime databaseUtcTime = DateTime.Parse("4/2/2016 6:25:20 PM");
    var localTimeTemp = databaseUtcTime.ToLocalTime();
    DateTime origDateTime = localTimeTemp.ToUniversalTime();

    //this is working
    //DateTime origDateTime = DateTime.Parse("4/2/2016 6:25:20 PM");
    
    string timeZoneName = "Pacific Standard Time";
    TimeZoneInfo localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneName);
    DateTimeOffset localTime = new DateTimeOffset(origDateTime, localTimeZone.GetUtcOffset(origDateTime));
    return localTime;
}
catch (Exception ex) {
    string msg = ex.Message;
    return null;
}

Solution

  • A few things:

    • If you really need to switch the Kind of a DateTime without adjusting its value, use DateTime.SpecifyKind. It is cleaner than dealing with ticks. However, I don't think you really need to do this.

    • Don't use ToLocalTime or ToUniversalTime. Both of these will use the time zone setting of the server in the conversion process.

    • I'm not sure that your real code is actually parsing a string, because you indicated that it is coming from the database. If it's coming from the database, then no string parsing should be involved. Just do the following:

      DateTime databaseUtcTime = (DateTime) yourDataReader["YourDataField"];
      
    • Once you have the input, you can then convert using the TimeZoneInfo.ConvertTime functions. Your existing code doesn't correctly convert the time, it just assigns an offset without correctly adjusting the time value.

      Since you wanted your output to be a datetimeoffset, then the easiest way is to first convert your input datetime to a datetimeoffset with zero for the offset (since it comes from UTC).

      DateTimeOffset dtoUtc = new DateTimeOffset(databaseUtcTime, TimeSpan.Zero);
      

      Then it's fairly simple to convert:

      string timeZoneName = "Pacific Standard Time";
      TimeZoneInfo localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneName);
      DateTimeOffset dtoLocal = TimeZoneInfo.ConvertTime(dtoUtc, localTimeZone);