Does .NET have the history of time zone changes?How does C# handle historical daylight saving time?Is there a flaw in Windows 7 Timezone rulesDateTime IsDaylightSavingTime() backwards compatibilityConversion from UTC to Timezone time produces different result with 4.0 and 3.5 SP1Getting a specific Time Zone in .net CF 3.5?Daylight saving time and time zone best practicesRussian time zone changesget DateTimeOffset from DateTime (utc) and TimeZoneInfoDjango timezone: feeling a bit confusedReliable time zone library or web service for PythonUTC to local time conversion for previously saved datetimes if rules for timezone changeMySQL - Turkey/Istanbul Daylight Saving Time ChangeConverting datetime (local or utc) to Moscow and Kiev timezone issues depending on DayLight saving timeHow to deal with time zone changes in Django?

Should I practice til I "get it" or until I'm sick of it?

What does a black-and-white Puerto Rican flag signify?

How does mathematics work?

My current job follows "worst practices". How can I talk about my experience in an interview without giving off red flags?

Calculating Fibonacci sequence in several different ways

Found more old paper shares from broken up companies

Are Linux kernel modules a sort of Linux system paged pool?

How old is the Italian word "malandrino"?

Why did computer video outputs go from digital to analog, then back to digital?

If hash functions append the length, why does length extension attack work?

Why can't a country print its own money to spend it only abroad?

Killing a star safely

Counterexample finite intersection property

Is it OK to accept a job opportunity while planning on not taking it?

Caption in landscape table, need help?

Facebook video calling problem in Safari

Acoustic guitar chords' positions vs those of a Bass guitar

Why didn't NASA launch communications relay satellites for the Apollo missions?

Is it ethical to tell my teaching assistant that I like him?

What is the best word describing the nature of expiring in a short amount of time, connoting "losing public attention"?

As a DM of a 4-player group, would it be appropriate for me to run a private 1-on-1 session so that one PC can act secretly?

What is a "staved" town, like in "Staverton"?

How can I deal with someone that wants to kill something that isn't supposed to be killed?

Why is a PhD thesis typically 150 pages?



Does .NET have the history of time zone changes?


How does C# handle historical daylight saving time?Is there a flaw in Windows 7 Timezone rulesDateTime IsDaylightSavingTime() backwards compatibilityConversion from UTC to Timezone time produces different result with 4.0 and 3.5 SP1Getting a specific Time Zone in .net CF 3.5?Daylight saving time and time zone best practicesRussian time zone changesget DateTimeOffset from DateTime (utc) and TimeZoneInfoDjango timezone: feeling a bit confusedReliable time zone library or web service for PythonUTC to local time conversion for previously saved datetimes if rules for timezone changeMySQL - Turkey/Istanbul Daylight Saving Time ChangeConverting datetime (local or utc) to Moscow and Kiev timezone issues depending on DayLight saving timeHow to deal with time zone changes in Django?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








15















Our government loves to change local time or enable|disable daylight saving time.



MS deployed patch for Russia to take new time change into account.



Now there is the question whether history of the changes exists?



When I get UTC time of the day in 01.01.2000 system should remember that Moscow time zone had +3 UTC. (in summer +4) at that moment.



For 01.01.2012 we had +4 UTC for both winter and summer. And soon we will have +3 UTC.



simple test shows that .NET does not keep records about the changes:



var t = new DateTime(2012,1,1);
// UTC +4 expected
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2012,06,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +3 expected
t = new DateTime(2000,1,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2000,6,1);
System.Console.WriteLine(t.ToLocalTime());


Does some additional API exist to cope with the problem?



Update:



Have found class TimeZoneInfo and related AdjustmentRule class. Left to test whether customization of TimeZoneInfo.Local time zone affects DateTime APIs.



Update 2:
Seems like UTC offsets are not stored as history and AdjustmentRule changes only daylight time during the year.










share|improve this question
























  • Take a look at DateTimeOffset. If you can capture the timezone offset as you capture the data you will be in better shape to display it and calculate against it.

    – Ian Mercer
    Oct 2 '14 at 18:18

















15















Our government loves to change local time or enable|disable daylight saving time.



MS deployed patch for Russia to take new time change into account.



Now there is the question whether history of the changes exists?



When I get UTC time of the day in 01.01.2000 system should remember that Moscow time zone had +3 UTC. (in summer +4) at that moment.



For 01.01.2012 we had +4 UTC for both winter and summer. And soon we will have +3 UTC.



simple test shows that .NET does not keep records about the changes:



var t = new DateTime(2012,1,1);
// UTC +4 expected
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2012,06,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +3 expected
t = new DateTime(2000,1,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2000,6,1);
System.Console.WriteLine(t.ToLocalTime());


Does some additional API exist to cope with the problem?



Update:



Have found class TimeZoneInfo and related AdjustmentRule class. Left to test whether customization of TimeZoneInfo.Local time zone affects DateTime APIs.



Update 2:
Seems like UTC offsets are not stored as history and AdjustmentRule changes only daylight time during the year.










share|improve this question
























  • Take a look at DateTimeOffset. If you can capture the timezone offset as you capture the data you will be in better shape to display it and calculate against it.

    – Ian Mercer
    Oct 2 '14 at 18:18













15












15








15


1






Our government loves to change local time or enable|disable daylight saving time.



MS deployed patch for Russia to take new time change into account.



Now there is the question whether history of the changes exists?



When I get UTC time of the day in 01.01.2000 system should remember that Moscow time zone had +3 UTC. (in summer +4) at that moment.



For 01.01.2012 we had +4 UTC for both winter and summer. And soon we will have +3 UTC.



simple test shows that .NET does not keep records about the changes:



var t = new DateTime(2012,1,1);
// UTC +4 expected
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2012,06,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +3 expected
t = new DateTime(2000,1,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2000,6,1);
System.Console.WriteLine(t.ToLocalTime());


Does some additional API exist to cope with the problem?



Update:



Have found class TimeZoneInfo and related AdjustmentRule class. Left to test whether customization of TimeZoneInfo.Local time zone affects DateTime APIs.



Update 2:
Seems like UTC offsets are not stored as history and AdjustmentRule changes only daylight time during the year.










share|improve this question
















Our government loves to change local time or enable|disable daylight saving time.



MS deployed patch for Russia to take new time change into account.



Now there is the question whether history of the changes exists?



When I get UTC time of the day in 01.01.2000 system should remember that Moscow time zone had +3 UTC. (in summer +4) at that moment.



For 01.01.2012 we had +4 UTC for both winter and summer. And soon we will have +3 UTC.



simple test shows that .NET does not keep records about the changes:



var t = new DateTime(2012,1,1);
// UTC +4 expected
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2012,06,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +3 expected
t = new DateTime(2000,1,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2000,6,1);
System.Console.WriteLine(t.ToLocalTime());


Does some additional API exist to cope with the problem?



Update:



Have found class TimeZoneInfo and related AdjustmentRule class. Left to test whether customization of TimeZoneInfo.Local time zone affects DateTime APIs.



Update 2:
Seems like UTC offsets are not stored as history and AdjustmentRule changes only daylight time during the year.







.net datetime timezone






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 2 '14 at 8:14







Pavel Voronin

















asked Oct 2 '14 at 7:38









Pavel VoroninPavel Voronin

7,6055 gold badges44 silver badges91 bronze badges




7,6055 gold badges44 silver badges91 bronze badges












  • Take a look at DateTimeOffset. If you can capture the timezone offset as you capture the data you will be in better shape to display it and calculate against it.

    – Ian Mercer
    Oct 2 '14 at 18:18

















  • Take a look at DateTimeOffset. If you can capture the timezone offset as you capture the data you will be in better shape to display it and calculate against it.

    – Ian Mercer
    Oct 2 '14 at 18:18
















Take a look at DateTimeOffset. If you can capture the timezone offset as you capture the data you will be in better shape to display it and calculate against it.

– Ian Mercer
Oct 2 '14 at 18:18





Take a look at DateTimeOffset. If you can capture the timezone offset as you capture the data you will be in better shape to display it and calculate against it.

– Ian Mercer
Oct 2 '14 at 18:18












3 Answers
3






active

oldest

votes


















7














.NET tracks some history, but it is not always accurate. You've stumbled upon one of the inaccuracies.



.NET imports all of it's time zone information from Windows via the registry, as described here and here. If you look in the registry at HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionTime ZonesRussian Standard TimeDynamic DST you'll find that it only tracks information from 2010 forward for this time zone. Testing dates in year 2000 is not going to work well, as it will fall back to the earliest rule available (2010).



Base UTC offset information is tracked in the registry, but not in the AdjustmentRule class that .NET imports it into. If you check the adjustment rules for this time zone, you'll find that 2012 and 2013 are not imported at all:



var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
foreach (var rule in tz.GetAdjustmentRules())

Console.WriteLine("0:d - 1:d", rule.DateStart, rule.DateEnd);



OUTPUT:



1/1/0001 - 12/31/2010
1/1/2011 - 12/31/2011
1/1/2014 - 12/31/2014


Even though they exist in the Windows registry, 2012 and 2013 are not imported because they have no daylight saving time adjustments.



This creates a problem when the base offset changes - like it has for this time zone. Since it is currently +3, and the two year where it was +4 were not imported, then it will look like it was +3 for those missing years.



There is no good solution for this using TimeZoneInfo. Even if you try to create your own custom time zones, you'll have trouble fitting this kind of change into the data structures available.



Fortunately, there is another option. You can use standard IANA time zones, via the Noda Time library.



The following code uses Noda Time to match what you wrote in your original code:



DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
Console.WriteLine(Instant.FromUtc(2012, 1, 1, 0, 0).InZone(tz).LocalDateTime);
Console.WriteLine(Instant.FromUtc(2012, 6, 1, 0, 0).InZone(tz).LocalDateTime);
Console.WriteLine(Instant.FromUtc(2000, 1, 1, 0, 0).InZone(tz).LocalDateTime);
Console.WriteLine(Instant.FromUtc(2000, 6, 1, 0, 0).InZone(tz).LocalDateTime);


If your local time zone is not already set for Moscow, you can change the first line to:



DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"];


OUTPUT:



1/1/2012 4:00:00 AM
6/1/2012 4:00:00 AM
1/1/2000 3:00:00 AM
6/1/2000 4:00:00 AM


Update



The problem described above of AdjustmentRule not tracking base offset changes was described in Microsoft Support article KB3012229, and subsequently fixed in .NET Framework 4.6 and also in .NET Core.



In the reference sources, one can see that AdjustmentRule now keeps a m_baseUtcOffsetDelta field. While this field is not exposed via a public property, it does factor in to the calculations, and it does reflect in serialization if you use the FromSerializedString and ToSerializedString methods (if anyone actually uses those).






share|improve this answer

























  • Something has changed a couple of days ago. Now 2012 and 2013 are imported. At least in .NET 4.5.2 (Win8.1, Win10) 1/1/0001 - 12/31/2010 1/1/2011 - 12/31/2011 1/1/2012 - 12/31/2012 1/1/2013 - 12/31/2013 1/1/2014 - 12/31/2014 But where is the data for 2015 and 2016?

    – Pavel Voronin
    Mar 2 '16 at 9:26












  • The last Russia change in 2014 dropped daylight saving time, so there are no adjustment rules for 2015 and later because there are no adjustments; the offset is fixed. The last offset of the last rule in the list should always apply from that time forward.

    – Matt Johnson
    Mar 2 '16 at 17:50











  • Also, though you're targeting 4.5.2, I'll guess you have 4.6 installed on the box so it's using the fix for KB3012229 that was implemented in 4.6 (the KB still needs to be updated to reflect that). The side effect is that you now see transition rules for 2012 and 2013 because it's now tracking base-offset changes correctly.

    – Matt Johnson
    Mar 2 '16 at 17:51






  • 1





    Lastly, be aware that there are new time zone changes coming to Russia this month. The Russian government has still not finalized all of them, and provided a very short notice effective date (grrr...). That means it's uncertain to whether they'll be a Windows update or hotfix in time to get in front of it, as Microsoft must wait for the government to make up their mind.

    – Matt Johnson
    Mar 2 '16 at 17:53











  • I added an update to the answer describing the changes. Thanks.

    – Matt Johnson
    Mar 2 '16 at 18:00


















2














you can try NodaTime,



http://nodatime.org/



better explanation of what is does



http://blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html






share|improve this answer























  • Noda Time - Yes, but link-only answers are discouraged on Stack Overflow.

    – Matt Johnson
    Oct 2 '14 at 19:07


















2














Historical time zone data is very complex and filled with many examples of small exceptions that apply in specific geographical regions that today have no easy way of being described. Not only are the offsets changing, but so are the regions to which they are applied.



There is a project to model the history of this data from around the world here:



  • http://www.iana.org/time-zones

  • http://en.wikipedia.org/wiki/Tz_database

.NET doesn't support what you want out of the box. Making a general solution to the problem will be very difficult, however if you only need it over a small set of regions, then you should be able to populate this yourself using the TimeZoneInfo class, the documentation for which states:




The members of the TimeZoneInfo class support the following operations:



  • Creating a new time zone that is not already defined by the operating system






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f26156260%2fdoes-net-have-the-history-of-time-zone-changes%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    7














    .NET tracks some history, but it is not always accurate. You've stumbled upon one of the inaccuracies.



    .NET imports all of it's time zone information from Windows via the registry, as described here and here. If you look in the registry at HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionTime ZonesRussian Standard TimeDynamic DST you'll find that it only tracks information from 2010 forward for this time zone. Testing dates in year 2000 is not going to work well, as it will fall back to the earliest rule available (2010).



    Base UTC offset information is tracked in the registry, but not in the AdjustmentRule class that .NET imports it into. If you check the adjustment rules for this time zone, you'll find that 2012 and 2013 are not imported at all:



    var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
    foreach (var rule in tz.GetAdjustmentRules())

    Console.WriteLine("0:d - 1:d", rule.DateStart, rule.DateEnd);



    OUTPUT:



    1/1/0001 - 12/31/2010
    1/1/2011 - 12/31/2011
    1/1/2014 - 12/31/2014


    Even though they exist in the Windows registry, 2012 and 2013 are not imported because they have no daylight saving time adjustments.



    This creates a problem when the base offset changes - like it has for this time zone. Since it is currently +3, and the two year where it was +4 were not imported, then it will look like it was +3 for those missing years.



    There is no good solution for this using TimeZoneInfo. Even if you try to create your own custom time zones, you'll have trouble fitting this kind of change into the data structures available.



    Fortunately, there is another option. You can use standard IANA time zones, via the Noda Time library.



    The following code uses Noda Time to match what you wrote in your original code:



    DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
    Console.WriteLine(Instant.FromUtc(2012, 1, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2012, 6, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2000, 1, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2000, 6, 1, 0, 0).InZone(tz).LocalDateTime);


    If your local time zone is not already set for Moscow, you can change the first line to:



    DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"];


    OUTPUT:



    1/1/2012 4:00:00 AM
    6/1/2012 4:00:00 AM
    1/1/2000 3:00:00 AM
    6/1/2000 4:00:00 AM


    Update



    The problem described above of AdjustmentRule not tracking base offset changes was described in Microsoft Support article KB3012229, and subsequently fixed in .NET Framework 4.6 and also in .NET Core.



    In the reference sources, one can see that AdjustmentRule now keeps a m_baseUtcOffsetDelta field. While this field is not exposed via a public property, it does factor in to the calculations, and it does reflect in serialization if you use the FromSerializedString and ToSerializedString methods (if anyone actually uses those).






    share|improve this answer

























    • Something has changed a couple of days ago. Now 2012 and 2013 are imported. At least in .NET 4.5.2 (Win8.1, Win10) 1/1/0001 - 12/31/2010 1/1/2011 - 12/31/2011 1/1/2012 - 12/31/2012 1/1/2013 - 12/31/2013 1/1/2014 - 12/31/2014 But where is the data for 2015 and 2016?

      – Pavel Voronin
      Mar 2 '16 at 9:26












    • The last Russia change in 2014 dropped daylight saving time, so there are no adjustment rules for 2015 and later because there are no adjustments; the offset is fixed. The last offset of the last rule in the list should always apply from that time forward.

      – Matt Johnson
      Mar 2 '16 at 17:50











    • Also, though you're targeting 4.5.2, I'll guess you have 4.6 installed on the box so it's using the fix for KB3012229 that was implemented in 4.6 (the KB still needs to be updated to reflect that). The side effect is that you now see transition rules for 2012 and 2013 because it's now tracking base-offset changes correctly.

      – Matt Johnson
      Mar 2 '16 at 17:51






    • 1





      Lastly, be aware that there are new time zone changes coming to Russia this month. The Russian government has still not finalized all of them, and provided a very short notice effective date (grrr...). That means it's uncertain to whether they'll be a Windows update or hotfix in time to get in front of it, as Microsoft must wait for the government to make up their mind.

      – Matt Johnson
      Mar 2 '16 at 17:53











    • I added an update to the answer describing the changes. Thanks.

      – Matt Johnson
      Mar 2 '16 at 18:00















    7














    .NET tracks some history, but it is not always accurate. You've stumbled upon one of the inaccuracies.



    .NET imports all of it's time zone information from Windows via the registry, as described here and here. If you look in the registry at HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionTime ZonesRussian Standard TimeDynamic DST you'll find that it only tracks information from 2010 forward for this time zone. Testing dates in year 2000 is not going to work well, as it will fall back to the earliest rule available (2010).



    Base UTC offset information is tracked in the registry, but not in the AdjustmentRule class that .NET imports it into. If you check the adjustment rules for this time zone, you'll find that 2012 and 2013 are not imported at all:



    var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
    foreach (var rule in tz.GetAdjustmentRules())

    Console.WriteLine("0:d - 1:d", rule.DateStart, rule.DateEnd);



    OUTPUT:



    1/1/0001 - 12/31/2010
    1/1/2011 - 12/31/2011
    1/1/2014 - 12/31/2014


    Even though they exist in the Windows registry, 2012 and 2013 are not imported because they have no daylight saving time adjustments.



    This creates a problem when the base offset changes - like it has for this time zone. Since it is currently +3, and the two year where it was +4 were not imported, then it will look like it was +3 for those missing years.



    There is no good solution for this using TimeZoneInfo. Even if you try to create your own custom time zones, you'll have trouble fitting this kind of change into the data structures available.



    Fortunately, there is another option. You can use standard IANA time zones, via the Noda Time library.



    The following code uses Noda Time to match what you wrote in your original code:



    DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
    Console.WriteLine(Instant.FromUtc(2012, 1, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2012, 6, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2000, 1, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2000, 6, 1, 0, 0).InZone(tz).LocalDateTime);


    If your local time zone is not already set for Moscow, you can change the first line to:



    DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"];


    OUTPUT:



    1/1/2012 4:00:00 AM
    6/1/2012 4:00:00 AM
    1/1/2000 3:00:00 AM
    6/1/2000 4:00:00 AM


    Update



    The problem described above of AdjustmentRule not tracking base offset changes was described in Microsoft Support article KB3012229, and subsequently fixed in .NET Framework 4.6 and also in .NET Core.



    In the reference sources, one can see that AdjustmentRule now keeps a m_baseUtcOffsetDelta field. While this field is not exposed via a public property, it does factor in to the calculations, and it does reflect in serialization if you use the FromSerializedString and ToSerializedString methods (if anyone actually uses those).






    share|improve this answer

























    • Something has changed a couple of days ago. Now 2012 and 2013 are imported. At least in .NET 4.5.2 (Win8.1, Win10) 1/1/0001 - 12/31/2010 1/1/2011 - 12/31/2011 1/1/2012 - 12/31/2012 1/1/2013 - 12/31/2013 1/1/2014 - 12/31/2014 But where is the data for 2015 and 2016?

      – Pavel Voronin
      Mar 2 '16 at 9:26












    • The last Russia change in 2014 dropped daylight saving time, so there are no adjustment rules for 2015 and later because there are no adjustments; the offset is fixed. The last offset of the last rule in the list should always apply from that time forward.

      – Matt Johnson
      Mar 2 '16 at 17:50











    • Also, though you're targeting 4.5.2, I'll guess you have 4.6 installed on the box so it's using the fix for KB3012229 that was implemented in 4.6 (the KB still needs to be updated to reflect that). The side effect is that you now see transition rules for 2012 and 2013 because it's now tracking base-offset changes correctly.

      – Matt Johnson
      Mar 2 '16 at 17:51






    • 1





      Lastly, be aware that there are new time zone changes coming to Russia this month. The Russian government has still not finalized all of them, and provided a very short notice effective date (grrr...). That means it's uncertain to whether they'll be a Windows update or hotfix in time to get in front of it, as Microsoft must wait for the government to make up their mind.

      – Matt Johnson
      Mar 2 '16 at 17:53











    • I added an update to the answer describing the changes. Thanks.

      – Matt Johnson
      Mar 2 '16 at 18:00













    7












    7








    7







    .NET tracks some history, but it is not always accurate. You've stumbled upon one of the inaccuracies.



    .NET imports all of it's time zone information from Windows via the registry, as described here and here. If you look in the registry at HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionTime ZonesRussian Standard TimeDynamic DST you'll find that it only tracks information from 2010 forward for this time zone. Testing dates in year 2000 is not going to work well, as it will fall back to the earliest rule available (2010).



    Base UTC offset information is tracked in the registry, but not in the AdjustmentRule class that .NET imports it into. If you check the adjustment rules for this time zone, you'll find that 2012 and 2013 are not imported at all:



    var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
    foreach (var rule in tz.GetAdjustmentRules())

    Console.WriteLine("0:d - 1:d", rule.DateStart, rule.DateEnd);



    OUTPUT:



    1/1/0001 - 12/31/2010
    1/1/2011 - 12/31/2011
    1/1/2014 - 12/31/2014


    Even though they exist in the Windows registry, 2012 and 2013 are not imported because they have no daylight saving time adjustments.



    This creates a problem when the base offset changes - like it has for this time zone. Since it is currently +3, and the two year where it was +4 were not imported, then it will look like it was +3 for those missing years.



    There is no good solution for this using TimeZoneInfo. Even if you try to create your own custom time zones, you'll have trouble fitting this kind of change into the data structures available.



    Fortunately, there is another option. You can use standard IANA time zones, via the Noda Time library.



    The following code uses Noda Time to match what you wrote in your original code:



    DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
    Console.WriteLine(Instant.FromUtc(2012, 1, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2012, 6, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2000, 1, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2000, 6, 1, 0, 0).InZone(tz).LocalDateTime);


    If your local time zone is not already set for Moscow, you can change the first line to:



    DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"];


    OUTPUT:



    1/1/2012 4:00:00 AM
    6/1/2012 4:00:00 AM
    1/1/2000 3:00:00 AM
    6/1/2000 4:00:00 AM


    Update



    The problem described above of AdjustmentRule not tracking base offset changes was described in Microsoft Support article KB3012229, and subsequently fixed in .NET Framework 4.6 and also in .NET Core.



    In the reference sources, one can see that AdjustmentRule now keeps a m_baseUtcOffsetDelta field. While this field is not exposed via a public property, it does factor in to the calculations, and it does reflect in serialization if you use the FromSerializedString and ToSerializedString methods (if anyone actually uses those).






    share|improve this answer















    .NET tracks some history, but it is not always accurate. You've stumbled upon one of the inaccuracies.



    .NET imports all of it's time zone information from Windows via the registry, as described here and here. If you look in the registry at HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionTime ZonesRussian Standard TimeDynamic DST you'll find that it only tracks information from 2010 forward for this time zone. Testing dates in year 2000 is not going to work well, as it will fall back to the earliest rule available (2010).



    Base UTC offset information is tracked in the registry, but not in the AdjustmentRule class that .NET imports it into. If you check the adjustment rules for this time zone, you'll find that 2012 and 2013 are not imported at all:



    var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
    foreach (var rule in tz.GetAdjustmentRules())

    Console.WriteLine("0:d - 1:d", rule.DateStart, rule.DateEnd);



    OUTPUT:



    1/1/0001 - 12/31/2010
    1/1/2011 - 12/31/2011
    1/1/2014 - 12/31/2014


    Even though they exist in the Windows registry, 2012 and 2013 are not imported because they have no daylight saving time adjustments.



    This creates a problem when the base offset changes - like it has for this time zone. Since it is currently +3, and the two year where it was +4 were not imported, then it will look like it was +3 for those missing years.



    There is no good solution for this using TimeZoneInfo. Even if you try to create your own custom time zones, you'll have trouble fitting this kind of change into the data structures available.



    Fortunately, there is another option. You can use standard IANA time zones, via the Noda Time library.



    The following code uses Noda Time to match what you wrote in your original code:



    DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
    Console.WriteLine(Instant.FromUtc(2012, 1, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2012, 6, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2000, 1, 1, 0, 0).InZone(tz).LocalDateTime);
    Console.WriteLine(Instant.FromUtc(2000, 6, 1, 0, 0).InZone(tz).LocalDateTime);


    If your local time zone is not already set for Moscow, you can change the first line to:



    DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"];


    OUTPUT:



    1/1/2012 4:00:00 AM
    6/1/2012 4:00:00 AM
    1/1/2000 3:00:00 AM
    6/1/2000 4:00:00 AM


    Update



    The problem described above of AdjustmentRule not tracking base offset changes was described in Microsoft Support article KB3012229, and subsequently fixed in .NET Framework 4.6 and also in .NET Core.



    In the reference sources, one can see that AdjustmentRule now keeps a m_baseUtcOffsetDelta field. While this field is not exposed via a public property, it does factor in to the calculations, and it does reflect in serialization if you use the FromSerializedString and ToSerializedString methods (if anyone actually uses those).







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Mar 2 '16 at 18:00

























    answered Oct 2 '14 at 18:11









    Matt JohnsonMatt Johnson

    150k47 gold badges300 silver badges424 bronze badges




    150k47 gold badges300 silver badges424 bronze badges












    • Something has changed a couple of days ago. Now 2012 and 2013 are imported. At least in .NET 4.5.2 (Win8.1, Win10) 1/1/0001 - 12/31/2010 1/1/2011 - 12/31/2011 1/1/2012 - 12/31/2012 1/1/2013 - 12/31/2013 1/1/2014 - 12/31/2014 But where is the data for 2015 and 2016?

      – Pavel Voronin
      Mar 2 '16 at 9:26












    • The last Russia change in 2014 dropped daylight saving time, so there are no adjustment rules for 2015 and later because there are no adjustments; the offset is fixed. The last offset of the last rule in the list should always apply from that time forward.

      – Matt Johnson
      Mar 2 '16 at 17:50











    • Also, though you're targeting 4.5.2, I'll guess you have 4.6 installed on the box so it's using the fix for KB3012229 that was implemented in 4.6 (the KB still needs to be updated to reflect that). The side effect is that you now see transition rules for 2012 and 2013 because it's now tracking base-offset changes correctly.

      – Matt Johnson
      Mar 2 '16 at 17:51






    • 1





      Lastly, be aware that there are new time zone changes coming to Russia this month. The Russian government has still not finalized all of them, and provided a very short notice effective date (grrr...). That means it's uncertain to whether they'll be a Windows update or hotfix in time to get in front of it, as Microsoft must wait for the government to make up their mind.

      – Matt Johnson
      Mar 2 '16 at 17:53











    • I added an update to the answer describing the changes. Thanks.

      – Matt Johnson
      Mar 2 '16 at 18:00

















    • Something has changed a couple of days ago. Now 2012 and 2013 are imported. At least in .NET 4.5.2 (Win8.1, Win10) 1/1/0001 - 12/31/2010 1/1/2011 - 12/31/2011 1/1/2012 - 12/31/2012 1/1/2013 - 12/31/2013 1/1/2014 - 12/31/2014 But where is the data for 2015 and 2016?

      – Pavel Voronin
      Mar 2 '16 at 9:26












    • The last Russia change in 2014 dropped daylight saving time, so there are no adjustment rules for 2015 and later because there are no adjustments; the offset is fixed. The last offset of the last rule in the list should always apply from that time forward.

      – Matt Johnson
      Mar 2 '16 at 17:50











    • Also, though you're targeting 4.5.2, I'll guess you have 4.6 installed on the box so it's using the fix for KB3012229 that was implemented in 4.6 (the KB still needs to be updated to reflect that). The side effect is that you now see transition rules for 2012 and 2013 because it's now tracking base-offset changes correctly.

      – Matt Johnson
      Mar 2 '16 at 17:51






    • 1





      Lastly, be aware that there are new time zone changes coming to Russia this month. The Russian government has still not finalized all of them, and provided a very short notice effective date (grrr...). That means it's uncertain to whether they'll be a Windows update or hotfix in time to get in front of it, as Microsoft must wait for the government to make up their mind.

      – Matt Johnson
      Mar 2 '16 at 17:53











    • I added an update to the answer describing the changes. Thanks.

      – Matt Johnson
      Mar 2 '16 at 18:00
















    Something has changed a couple of days ago. Now 2012 and 2013 are imported. At least in .NET 4.5.2 (Win8.1, Win10) 1/1/0001 - 12/31/2010 1/1/2011 - 12/31/2011 1/1/2012 - 12/31/2012 1/1/2013 - 12/31/2013 1/1/2014 - 12/31/2014 But where is the data for 2015 and 2016?

    – Pavel Voronin
    Mar 2 '16 at 9:26






    Something has changed a couple of days ago. Now 2012 and 2013 are imported. At least in .NET 4.5.2 (Win8.1, Win10) 1/1/0001 - 12/31/2010 1/1/2011 - 12/31/2011 1/1/2012 - 12/31/2012 1/1/2013 - 12/31/2013 1/1/2014 - 12/31/2014 But where is the data for 2015 and 2016?

    – Pavel Voronin
    Mar 2 '16 at 9:26














    The last Russia change in 2014 dropped daylight saving time, so there are no adjustment rules for 2015 and later because there are no adjustments; the offset is fixed. The last offset of the last rule in the list should always apply from that time forward.

    – Matt Johnson
    Mar 2 '16 at 17:50





    The last Russia change in 2014 dropped daylight saving time, so there are no adjustment rules for 2015 and later because there are no adjustments; the offset is fixed. The last offset of the last rule in the list should always apply from that time forward.

    – Matt Johnson
    Mar 2 '16 at 17:50













    Also, though you're targeting 4.5.2, I'll guess you have 4.6 installed on the box so it's using the fix for KB3012229 that was implemented in 4.6 (the KB still needs to be updated to reflect that). The side effect is that you now see transition rules for 2012 and 2013 because it's now tracking base-offset changes correctly.

    – Matt Johnson
    Mar 2 '16 at 17:51





    Also, though you're targeting 4.5.2, I'll guess you have 4.6 installed on the box so it's using the fix for KB3012229 that was implemented in 4.6 (the KB still needs to be updated to reflect that). The side effect is that you now see transition rules for 2012 and 2013 because it's now tracking base-offset changes correctly.

    – Matt Johnson
    Mar 2 '16 at 17:51




    1




    1





    Lastly, be aware that there are new time zone changes coming to Russia this month. The Russian government has still not finalized all of them, and provided a very short notice effective date (grrr...). That means it's uncertain to whether they'll be a Windows update or hotfix in time to get in front of it, as Microsoft must wait for the government to make up their mind.

    – Matt Johnson
    Mar 2 '16 at 17:53





    Lastly, be aware that there are new time zone changes coming to Russia this month. The Russian government has still not finalized all of them, and provided a very short notice effective date (grrr...). That means it's uncertain to whether they'll be a Windows update or hotfix in time to get in front of it, as Microsoft must wait for the government to make up their mind.

    – Matt Johnson
    Mar 2 '16 at 17:53













    I added an update to the answer describing the changes. Thanks.

    – Matt Johnson
    Mar 2 '16 at 18:00





    I added an update to the answer describing the changes. Thanks.

    – Matt Johnson
    Mar 2 '16 at 18:00













    2














    you can try NodaTime,



    http://nodatime.org/



    better explanation of what is does



    http://blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html






    share|improve this answer























    • Noda Time - Yes, but link-only answers are discouraged on Stack Overflow.

      – Matt Johnson
      Oct 2 '14 at 19:07















    2














    you can try NodaTime,



    http://nodatime.org/



    better explanation of what is does



    http://blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html






    share|improve this answer























    • Noda Time - Yes, but link-only answers are discouraged on Stack Overflow.

      – Matt Johnson
      Oct 2 '14 at 19:07













    2












    2








    2







    you can try NodaTime,



    http://nodatime.org/



    better explanation of what is does



    http://blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html






    share|improve this answer













    you can try NodaTime,



    http://nodatime.org/



    better explanation of what is does



    http://blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Oct 2 '14 at 8:19









    dariogriffodariogriffo

    2,88912 silver badges24 bronze badges




    2,88912 silver badges24 bronze badges












    • Noda Time - Yes, but link-only answers are discouraged on Stack Overflow.

      – Matt Johnson
      Oct 2 '14 at 19:07

















    • Noda Time - Yes, but link-only answers are discouraged on Stack Overflow.

      – Matt Johnson
      Oct 2 '14 at 19:07
















    Noda Time - Yes, but link-only answers are discouraged on Stack Overflow.

    – Matt Johnson
    Oct 2 '14 at 19:07





    Noda Time - Yes, but link-only answers are discouraged on Stack Overflow.

    – Matt Johnson
    Oct 2 '14 at 19:07











    2














    Historical time zone data is very complex and filled with many examples of small exceptions that apply in specific geographical regions that today have no easy way of being described. Not only are the offsets changing, but so are the regions to which they are applied.



    There is a project to model the history of this data from around the world here:



    • http://www.iana.org/time-zones

    • http://en.wikipedia.org/wiki/Tz_database

    .NET doesn't support what you want out of the box. Making a general solution to the problem will be very difficult, however if you only need it over a small set of regions, then you should be able to populate this yourself using the TimeZoneInfo class, the documentation for which states:




    The members of the TimeZoneInfo class support the following operations:



    • Creating a new time zone that is not already defined by the operating system






    share|improve this answer



























      2














      Historical time zone data is very complex and filled with many examples of small exceptions that apply in specific geographical regions that today have no easy way of being described. Not only are the offsets changing, but so are the regions to which they are applied.



      There is a project to model the history of this data from around the world here:



      • http://www.iana.org/time-zones

      • http://en.wikipedia.org/wiki/Tz_database

      .NET doesn't support what you want out of the box. Making a general solution to the problem will be very difficult, however if you only need it over a small set of regions, then you should be able to populate this yourself using the TimeZoneInfo class, the documentation for which states:




      The members of the TimeZoneInfo class support the following operations:



      • Creating a new time zone that is not already defined by the operating system






      share|improve this answer

























        2












        2








        2







        Historical time zone data is very complex and filled with many examples of small exceptions that apply in specific geographical regions that today have no easy way of being described. Not only are the offsets changing, but so are the regions to which they are applied.



        There is a project to model the history of this data from around the world here:



        • http://www.iana.org/time-zones

        • http://en.wikipedia.org/wiki/Tz_database

        .NET doesn't support what you want out of the box. Making a general solution to the problem will be very difficult, however if you only need it over a small set of regions, then you should be able to populate this yourself using the TimeZoneInfo class, the documentation for which states:




        The members of the TimeZoneInfo class support the following operations:



        • Creating a new time zone that is not already defined by the operating system






        share|improve this answer













        Historical time zone data is very complex and filled with many examples of small exceptions that apply in specific geographical regions that today have no easy way of being described. Not only are the offsets changing, but so are the regions to which they are applied.



        There is a project to model the history of this data from around the world here:



        • http://www.iana.org/time-zones

        • http://en.wikipedia.org/wiki/Tz_database

        .NET doesn't support what you want out of the box. Making a general solution to the problem will be very difficult, however if you only need it over a small set of regions, then you should be able to populate this yourself using the TimeZoneInfo class, the documentation for which states:




        The members of the TimeZoneInfo class support the following operations:



        • Creating a new time zone that is not already defined by the operating system







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Oct 2 '14 at 8:25









        Drew NoakesDrew Noakes

        197k124 gold badges542 silver badges636 bronze badges




        197k124 gold badges542 silver badges636 bronze badges



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f26156260%2fdoes-net-have-the-history-of-time-zone-changes%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

            Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

            Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript