Reputation: 882
It seems we have found an issue with RTZ2 timezone (Russian Standard Time) in .Net Framework 4.5.
If you try to convert time between 2014-01-01 00:00:00 and 2014-01-01 00:59:59 (in RTZ2 timezone) to UTC, you get an error: The supplied DateTime represents an invalid time. For example, when the clock is adjusted forward, any time in the period that is skipped is invalid.
Example (https://dotnetfiddle.net/rNbp8F):
var rtz2 = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
var moment = new DateTime(2014, 1, 1);
var utc = TimeZoneInfo.ConvertTimeToUtc(moment, rtz2); // throws an exception
Any ideas how to fix this?
Upvotes: 3
Views: 796
Reputation: 241758
This is probably related to KB3012229, which was fixed with .NET 4.6.
If you have .NET 4.6 installed, the exception will not be thrown - even if you are targeting .NET 4.0 through 4.5.2 - because they are all in-place upgrades.
The exception does reproduce on .NET 3.5, or on .NET 4.0 through .NET 4.5.2 if you do not have .NET 4.6 installed.
There are a few things you can do here:
Option 1: Leave your code as-is, and update to the latest .NET 4.6 (or install one of the hotfixes now available in the KB article)
Option 2: Change your code to use a function such as this:
private DateTime Rtz2ToUtc(DateTime dt)
{
if (dt.Kind == DateTimeKind.Utc)
return dt;
if (dt.Year < 2011)
{
var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
return TimeZoneInfo.ConvertTimeToUtc(dt, tz);
}
var transition = new DateTime(2014, 10, 26, 2, 0, 0);
var offset = TimeSpan.FromHours(dt < transition ? 4 : 3);
return new DateTimeOffset(dt, offset).UtcDateTime;
}
Option 3: Change your code to use Noda Time and TZDB time zones:
private DateTime Rtz2ToUtc(DateTime dt)
{
if (dt.Kind == DateTimeKind.Utc)
return dt;
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"];
LocalDateTime ldt = LocalDateTime.FromDateTime(dt);
return ldt.InZoneLeniently(tz).ToDateTimeUtc();
}
Personally, I prefer Option 3, as TZDB time zones are much more accurate than Windows time zones. You can read more in the timezone tag wiki.
Upvotes: 2
Reputation: 870
Try this out :
var rtz2 = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
var offset = new DateTimeOffset(new DateTime(2014, 1, 1));
var timeSpan = rtz2.GetUtcOffset(offset);
You can now create the UTC DateTime by using timeSpan :
var utc = offset.Add(timeSpan);
// 1/1/2014 4:00:00 AM -06:00
Upvotes: -1