Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. .NET (Core and Framework)
  4. TimeZone.CurrentTimeZone not updated when machine's time zone changes.

TimeZone.CurrentTimeZone not updated when machine's time zone changes.

Scheduled Pinned Locked Moved .NET (Core and Framework)
csharphelptutorialquestionannouncement
7 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Matt Casto
    wrote on last edited by
    #1

    I have a C# windows service that depends on time comparisons that is encountering problems due to the time zone on the machine being changed. Unfortunately, this time zone change is outside of my control. I use the TimeZone.CurrentTimeZone.ToUniversalTime() and TimeZone.CurrentTimeZone.GetUtcOffset() methods to make sure all my times are converted and compared as UTC. The problem is that TimeZone.CurrentTimeZone is not updating when the machine's time zone has changed. You can reproduce this easily by creating a console app with the following lines of code, and manually changing your machine's time zone during the app's pause. Console.WriteLine("Current time zone is {0}.", TimeZone.CurrentTimeZone.StandardName); Console.Write("Waiting for time zone change. Hit 'Enter' to continue ..."); Console.ReadLine(); // manually change time zone here before app continues Console.WriteLine("Current time zone is {0}.", TimeZone.CurrentTimeZone.StandardName); Does anyone have any idea about how to refresh or update the TimeZone.CurrentTimeZone? Thanks!

    M Richard DeemingR 2 Replies Last reply
    0
    • M Matt Casto

      I have a C# windows service that depends on time comparisons that is encountering problems due to the time zone on the machine being changed. Unfortunately, this time zone change is outside of my control. I use the TimeZone.CurrentTimeZone.ToUniversalTime() and TimeZone.CurrentTimeZone.GetUtcOffset() methods to make sure all my times are converted and compared as UTC. The problem is that TimeZone.CurrentTimeZone is not updating when the machine's time zone has changed. You can reproduce this easily by creating a console app with the following lines of code, and manually changing your machine's time zone during the app's pause. Console.WriteLine("Current time zone is {0}.", TimeZone.CurrentTimeZone.StandardName); Console.Write("Waiting for time zone change. Hit 'Enter' to continue ..."); Console.ReadLine(); // manually change time zone here before app continues Console.WriteLine("Current time zone is {0}.", TimeZone.CurrentTimeZone.StandardName); Does anyone have any idea about how to refresh or update the TimeZone.CurrentTimeZone? Thanks!

      M Offline
      M Offline
      Matt Casto
      wrote on last edited by
      #2

      I think I found a work-around, but I don't fully like it. If I call the GetSystemTime WinAPI function, it seems to always return the correct UTC time. I got some decent sample code from Anson Goldade's GotDotNet user sample to nicely encapsulate the API calls. Too bad Microsoft's framework methods don't call the API correctly.

      1 Reply Last reply
      0
      • M Matt Casto

        I have a C# windows service that depends on time comparisons that is encountering problems due to the time zone on the machine being changed. Unfortunately, this time zone change is outside of my control. I use the TimeZone.CurrentTimeZone.ToUniversalTime() and TimeZone.CurrentTimeZone.GetUtcOffset() methods to make sure all my times are converted and compared as UTC. The problem is that TimeZone.CurrentTimeZone is not updating when the machine's time zone has changed. You can reproduce this easily by creating a console app with the following lines of code, and manually changing your machine's time zone during the app's pause. Console.WriteLine("Current time zone is {0}.", TimeZone.CurrentTimeZone.StandardName); Console.Write("Waiting for time zone change. Hit 'Enter' to continue ..."); Console.ReadLine(); // manually change time zone here before app continues Console.WriteLine("Current time zone is {0}.", TimeZone.CurrentTimeZone.StandardName); Does anyone have any idea about how to refresh or update the TimeZone.CurrentTimeZone? Thanks!

        Richard DeemingR Online
        Richard DeemingR Online
        Richard Deeming
        wrote on last edited by
        #3

        The problem is that the CurrentTimeZone property caches the result for the lifetime of the AppDomain, so you won't see any changes until your AppDomain is restarted. The simplest option is to use reflection to create a new instance of the internal CurrentSystemTimeZone class. The following code will cache the current time zone for 5 minutes, and allow you to manually refresh the time zone as well:

        using System;
        using System.Reflection;

        public sealed class CurrentTimeZone
        {
        private const int RefreshAfterMinutes = 5;
        private static readonly object _lockMe = new object();
        private static readonly Type _timeZoneType;
        private static readonly ConstructorInfo _timeZoneConstructor;
        private static TimeZone _instance = TimeZone.CurrentTimeZone;
        private static DateTime _instanceCreated = DateTime.UtcNow;

        static CurrentTimeZone()
        {
            \_timeZoneType = TimeZone.CurrentTimeZone.GetType();
            \_timeZoneConstructor = \_timeZoneType.GetConstructor(
                BindingFlags.Instance | BindingFlags.NonPublic,
                null, new Type\[0\], null);
        }
        
        private static TimeZone CreateInstance()
        {
            return (TimeZone)\_timeZoneConstructor.Invoke(null);
        }
        
        private static void UpdateIfStale()
        {
            TimeSpan age = \_instanceCreated - DateTime.UtcNow;
            if (age.TotalMinutes > RefreshAfterMinutes)
            {
                \_instance = CreateInstance();
                \_instanceCreated = DateTime.UtcNow;
            }
        }
        
        public static TimeZone Instance
        {
            get
            {
                lock(\_lockMe)
                {
                    UpdateIfStale();
                    return \_instance;
                }
            }
        }
        
        public static void Refresh()
        {
            lock(\_lockMe)
            {
                \_instance = CreateInstance();
                \_instanceCreated = DateTime.UtcNow;
            }
        }
        

        }

        All you need to do is replace each instance of TimeZone.CurrentTimeZone with CurrentTimeZone.Instance, and you should see the changes within 5 minutes.


        "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

        "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

        M 1 Reply Last reply
        0
        • Richard DeemingR Richard Deeming

          The problem is that the CurrentTimeZone property caches the result for the lifetime of the AppDomain, so you won't see any changes until your AppDomain is restarted. The simplest option is to use reflection to create a new instance of the internal CurrentSystemTimeZone class. The following code will cache the current time zone for 5 minutes, and allow you to manually refresh the time zone as well:

          using System;
          using System.Reflection;

          public sealed class CurrentTimeZone
          {
          private const int RefreshAfterMinutes = 5;
          private static readonly object _lockMe = new object();
          private static readonly Type _timeZoneType;
          private static readonly ConstructorInfo _timeZoneConstructor;
          private static TimeZone _instance = TimeZone.CurrentTimeZone;
          private static DateTime _instanceCreated = DateTime.UtcNow;

          static CurrentTimeZone()
          {
              \_timeZoneType = TimeZone.CurrentTimeZone.GetType();
              \_timeZoneConstructor = \_timeZoneType.GetConstructor(
                  BindingFlags.Instance | BindingFlags.NonPublic,
                  null, new Type\[0\], null);
          }
          
          private static TimeZone CreateInstance()
          {
              return (TimeZone)\_timeZoneConstructor.Invoke(null);
          }
          
          private static void UpdateIfStale()
          {
              TimeSpan age = \_instanceCreated - DateTime.UtcNow;
              if (age.TotalMinutes > RefreshAfterMinutes)
              {
                  \_instance = CreateInstance();
                  \_instanceCreated = DateTime.UtcNow;
              }
          }
          
          public static TimeZone Instance
          {
              get
              {
                  lock(\_lockMe)
                  {
                      UpdateIfStale();
                      return \_instance;
                  }
              }
          }
          
          public static void Refresh()
          {
              lock(\_lockMe)
              {
                  \_instance = CreateInstance();
                  \_instanceCreated = DateTime.UtcNow;
              }
          }
          

          }

          All you need to do is replace each instance of TimeZone.CurrentTimeZone with CurrentTimeZone.Instance, and you should see the changes within 5 minutes.


          "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

          M Offline
          M Offline
          Matt Casto
          wrote on last edited by
          #4

          Unfortunately, I need to know the time zone at the exact moment that the code runs, and even 5 minutes late could cause issues. Anyway, while it's pretty cool, do you really think that your class is the simplest way to fix the problem when you can just call the GetSystemTime API?

          Richard DeemingR 1 Reply Last reply
          0
          • M Matt Casto

            Unfortunately, I need to know the time zone at the exact moment that the code runs, and even 5 minutes late could cause issues. Anyway, while it's pretty cool, do you really think that your class is the simplest way to fix the problem when you can just call the GetSystemTime API?

            Richard DeemingR Online
            Richard DeemingR Online
            Richard Deeming
            wrote on last edited by
            #5

            If you just need the current UTC system time, you can simply call DateTime.UtcNow, which will return the same time as calling the GetSystemTime API. From your initial post, it sounded like you need the current time zone information as well, in which case the code I posted will be the simplest solution. If you want the current time zone information without any caching, you can simply remove the caching code and always return a new instance:

            using System;
            using System.Reflection;

            public sealed class CurrentTimeZone
            {
            private static readonly Type _timeZoneType;
            private static readonly ConstructorInfo _timeZoneConstructor;

            static CurrentTimeZone()
            {
                \_timeZoneType = TimeZone.CurrentTimeZone.GetType();
                \_timeZoneConstructor = \_timeZoneType.GetConstructor(
                    BindingFlags.Instance | BindingFlags.NonPublic,
                    null, new Type\[0\], null);
            }
            
            private static TimeZone CreateInstance()
            {
                return (TimeZone)\_timeZoneConstructor.Invoke(null);
            }
            
            public static TimeZone Instance
            {
                get { return CreateInstance(); }
            }
            

            }


            "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

            "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

            M 1 Reply Last reply
            0
            • Richard DeemingR Richard Deeming

              If you just need the current UTC system time, you can simply call DateTime.UtcNow, which will return the same time as calling the GetSystemTime API. From your initial post, it sounded like you need the current time zone information as well, in which case the code I posted will be the simplest solution. If you want the current time zone information without any caching, you can simply remove the caching code and always return a new instance:

              using System;
              using System.Reflection;

              public sealed class CurrentTimeZone
              {
              private static readonly Type _timeZoneType;
              private static readonly ConstructorInfo _timeZoneConstructor;

              static CurrentTimeZone()
              {
                  \_timeZoneType = TimeZone.CurrentTimeZone.GetType();
                  \_timeZoneConstructor = \_timeZoneType.GetConstructor(
                      BindingFlags.Instance | BindingFlags.NonPublic,
                      null, new Type\[0\], null);
              }
              
              private static TimeZone CreateInstance()
              {
                  return (TimeZone)\_timeZoneConstructor.Invoke(null);
              }
              
              public static TimeZone Instance
              {
                  get { return CreateInstance(); }
              }
              

              }


              "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

              M Offline
              M Offline
              Matt Casto
              wrote on last edited by
              #6

              Thanks, this code will be very useful to me. However, I just want to point out that in my tests DateTime.UtcNow doesn't return the correct time because of the time zone caching. You can try it yourself by using a test similar to the first one I posted.

              Richard DeemingR 1 Reply Last reply
              0
              • M Matt Casto

                Thanks, this code will be very useful to me. However, I just want to point out that in my tests DateTime.UtcNow doesn't return the correct time because of the time zone caching. You can try it yourself by using a test similar to the first one I posted.

                Richard DeemingR Online
                Richard DeemingR Online
                Richard Deeming
                wrote on last edited by
                #7

                That's very strange. The DateTime.UtcNow property simply calls the GetSystemTimeAsFileTime API to get the current UTC system time. There is no caching involved, so the result should be the same as calling the GetSystemTime API directly.


                "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups