DateTimeOffset parse and custom time zone

6.4k views Asked by At

We are parsing XML DateTime values into a DateTimeOffset value. According to the W3C XSD documentation for DateTime, the type may have a timezone info or not.

Our requirment says:

  • If time zone info is provided in XML, use this time zone
  • If no time zone info is provided, assume it's a local time in a predefined, configurable time zone (not the one from Server).

The Problem is that when a XML DateTime without a time zone is parsed into a DateTimeOffset, it uses the local (System) timezone by default. It seems not possible to override the default timezone and also not possible to identify wheter the timezone was parsed or added internally.

Is there any way I can specify the default timezone used by the DateTimeOffset parsing?
If not, how can one identify if the time zone was parsed or added automatically during parsing for DateTimeOffset?

It seems strange to me that there is no support to set the time zone for a .NET application the same way as one can set the current culture.

Therefore the only approach to this problem seems to first parse the value into DateTime and check the Kind property. If Kind is not Unspecified, parse the value again into a DateTimeOffset:

/*
sample values:
- 2015-06-03T10:47:01
- 2015-06-03T07:47:01Z
- 2015-06-03T10:47:01+03:00
*/

DateTimeOffset dto;
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["DefaultTimeZone"]);
var dt = DateTime.Parse(value);

if (dt.Kind == DateTimeKind.Unspecified)
{
    dto = new DateTimeOffset(dt, timeZone.GetUtcOffset(dt));
}
else
{
    dto = DateTimeOffset.Parse(value);
}
1

There are 1 answers

0
Matt Johnson-Pint On BEST ANSWER

The simplest way would be to test the string ahead of time to see if it contains an offset. Regular expressions work well for this.

Here is a function that should work well for the case you described:

static DateTimeOffset ParseAsDateTimeOffset(string s, TimeSpan defaultOffset)
{
    if (Regex.IsMatch(s, @"(Z|[+-]\d{2}:\d{2})$"))
        return DateTimeOffset.Parse(s, CultureInfo.InvariantCulture);

    var dt = DateTime.Parse(s, CultureInfo.InvariantCulture);
    return new DateTimeOffset(dt, defaultOffset);
}

You might also consider a slight variation of that, which is to provide a default time zone, rather than a default offset. This is an important distinction, since the offset of a time zone can change depending on whether the specific date is in a daylight saving time period or not. See also "Time Zone != Offset" in the timezone tag wiki.

static DateTimeOffset ParseAsDateTimeOffset(string s, TimeZoneInfo defaultTimeZone)
{
    if (Regex.IsMatch(s, @"(Z|[+-]\d{2}:\d{2})$"))
        return DateTimeOffset.Parse(s, CultureInfo.InvariantCulture);

    var dt = DateTime.Parse(s, CultureInfo.InvariantCulture);
    return new DateTimeOffset(dt, defaultTimeZone.GetUtcOffset(dt));
}