1

I'm getting a following string from a web service 2013-10-15T12:54:18+01:00. This date is in the summer DST and my .NET code (web service proxy, I presume) automatically adds one hour to it. The same is not the case if the returned value falls withing the winter DST. The time returned (12:54:18) is what I want to display, I don't want any sort of recalculation to be done.

I'm using TimeSpan DateTime.TimeOfDay to show the time.

What can I do to make it happen?

Robotronx
  • 1,728
  • 2
  • 21
  • 43
  • 3
    "summer DST" is useless information. There's many 'summer' time zones. – Marc B Jan 12 '15 at 14:58
  • I don't see any "summer DST" here, just a DateTimeOffset value with an offset of "1:00". If you try to convert it to a DateTime object .NET will check your local timezone offset and create the corresponding DateTime value. Are you confusing the timezone offset with summer time? – Panagiotis Kanavos Jan 12 '15 at 15:13
  • Are you converting the DateTimeOffset value to a DateTime? CE time during summer **is +2:00** while during winter it's +1. Your wall clock on `2013-10-15T12:54:18+01:00` **will display** 13:54. When .NET converts to local time it takes this into consideration to create the correct value. – Panagiotis Kanavos Jan 12 '15 at 15:29
  • To put it another way, an airplane leaving at `2013-10-15T12:54:18+01:00` from a CE airport would have a local departure time of `13:54`. To avoid such confusions airlines either post local times only, or use the timezone's name, not the offset. If an offset is returned, it's always the actual local offset. – Panagiotis Kanavos Jan 12 '15 at 15:33
  • 1
    I'm calling a web service from my C# code and get this value back (DateTime type). When I scan network traffic I see that the string mentioned `2013-10-15T12:54:18+01:00` is sent across the wire. – Robotronx Jan 12 '15 at 18:22
  • @PanagiotisKanavos "Are you confusing the timezone offset with summer time?" - `+01:00` looks like a timezone to me (and I am located in a +01:00 time zone), however when the date is in the winter DST, this piece of string is missing, e.g. `2013-12-30T12:54:18`. – Robotronx Jan 12 '15 at 18:34

3 Answers3

3

I am trying to put the pieces together from your question and the additional comments. So far this is my analysis:

  1. On the wire you see two different date and time strings:

    • Without daylight savings (winter) the string is 2013-12-30T12:54:18

    • With daylight savings (summer) the string is 2013-10-15T12:54:18+01:00

    This is a sign that the web service is using GMT Standard Time as the time zone.

  2. You want to extract the GMT timestamp from the date and time string.

  3. However, between you and the web service there is some unspecified web service proxy (I assume some kind of .NET framework?) and in your code you only have access to a DateTime and furthermore your code is executing in the Central Europe Standard Time time zone which basically is one hour ahead of GMT both during summer and winter if we disregard the short time where there is a transition to and from daylight savings.

I hope I am correct so far.

You can convert the incoming DateTime to GMT using this code:

// Framework code creates the DateTime.
var sourceDateTime = DateTime.Parse("2013-10-15T12:54:18+01:00");
// Application code can further process the DateTime.
var destinationTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
var destinationDateTime = TimeZoneInfo.ConvertTime(sourceDateTime, destinationTimeZoneInfo);

This example gives the correct answer during daylight savings. The incoming date and time string contains an offset and is correctly parsed into a local time zone (CET). The TimeZoneInfo.ConvertTime assumes that the source DateTime is in the local time zone and the result is correct.

However, the code fails during winter where there is no daylight savings:

var sourceDateTime = DateTime.Parse("2013-12-30T12:54:18");

Notice that the date and time string no longer contains a time zone offset. The offset is +00:00 but for some reason it is missing from the string. This means that the source DateTime is assumed to be in the local time zone (CET) and not converted from the actual time zone (GMT). This is the source of your problem if my analysis is correct.

Another way to explain it:

       | Server (GMT)  | Framework (CET)           | My code
-------+---------------+---------------------------+----------------------------
Summer | +01:00 suffix | GMT -> CET adds 1 hour    | CET -> GMT subtracts 1 hour
-------+---------------+---------------------------+----------------------------
Winter | No suffix     | Assumed to be CET         | CET -> GMT subtracts 1 hour

There is no easy fix for this problem. If you could persuade the web service to provide the correct offset even when it is +00:00 my code above would work both summer and winter. Even better, only use UTC and only convert to a local time when the end-user gets involved. But I guess that you have no control over the web service?

One option would be to execute your code in the same time zone as the server (e.g. GMT). Then you should be able to use the timestamp directly without any conversion.

Another more ugly option is to determine if the web service is outside daylight savings and then adjust the time accordingly:

var destinationTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
if (!destinationTimeZoneInfo.IsDaylightSavingTime(sourceDateTime)) {
  var sourceDateTimeOffset = new DateTimeOffset(sourceDateTime, destinationTimeZoneInfo.BaseUtcOffset);
  sourceDateTime = sourceDateTimeOffset.UtcDateTime;
}
var destinationDateTime = TimeZoneInfo.ConvertTime(sourceDateTime, destinationTimeZoneInfo);

I have tried to keep the code as general as possible but actually it is only trying to fix the situation where +00:00 is missing and in that case destinationTimeZoneInfo.BaseUtcOffset is precisely 0 so it might be slightly overkill to do it like this.

More importantly, I am not sure that this code provides the correct results during the time when there is a daylight savings transition. Even though I believe that GMT and CET transitions at the same date CET is still one hour ahead of GMT. You really have to create some unit tests to make sure you get the desired result.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
  • The time value retrieved by the web service in question was created in the same time zone as I am in. In addition, I have no way to get the string `2013-10-15T12:54:18+01:00`. I see this string when I scan network traffic, but in my code I only have access to C# type of DateTime (courtesy of web service proxy) and its `TimeOfDay` property. An interesting thing: all the timestamps (when scanning network traffic) that contain a date in the winter DST don't have the `+01:00`. – Robotronx Jan 12 '15 at 18:29
  • "It is not entirely clear from your question what you want to do" - for the string mentioned (as scanned on the wire `2013-10-15T12:54:18+01:00`), I want to display `12:54:18`. For dates in the winter DST, I'm getting `2013-12-30T12:54:18` (note the missing `+01:00`), and for such a string I also want to display `12:54:18`. – Robotronx Jan 12 '15 at 18:38
  • 1
    @Robotron: I have completely rewritten my answer to hopefully better address your question. – Martin Liversage Jan 12 '15 at 22:40
  • It seems the test system didn't work the same as the production. The `+01:00` mentioned appeared only for summer DST in the test environment, but not on production. Spent a lot of time until I figured this one out. In the end I just tested with `DateTime.IsDaylightSavingTime()`. – Robotronx Jan 13 '15 at 09:49
2

A DateTime object does not contain offset in this kind of example. It only holds a kind which could be i.e.: local offset (offset of the runtime environment) or UTC. Do it like so, since DateTimeOffset is what you want:

DateTimeOffset test = DateTimeOffset.Parse("2013-10-15T12:54:18+01:00");

Console.WriteLine(test.DateTime.TimeOfDay); // UTC
Console.WriteLine(test.LocalDateTime.TimeOfDay); // Localized with the offset parsed

Will output

12:54:18
11:54:18
Nick O
  • 116
  • 4
1

You might want to check this MSDN article which describes the transitions that your TimeOfDay is currently returning.

By examining that article, you can find the way on how to correct it. TimeZoneInfo is the class that you'll need.

Edit, the work that Jon Skeet provided might help as well, look at the Noda Time blogspot for more info!

RvdV79
  • 2,002
  • 16
  • 36