问题
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?
回答1:
I am trying to put the pieces together from your question and the additional comments. So far this is my analysis:
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.
You want to extract the GMT timestamp from the date and time string.
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.
回答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
回答3:
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!
来源:https://stackoverflow.com/questions/27904806/net-adds-one-hour-to-summer-dst