none
Changing Time Zone with C#... Hmmmmm RRS feed

  • Question

  •  

    Hey everybody,

     

    I'm trying to set the time zone with C# code... after I run the following code and I look at the time zone properties in control panel, the offset is indeed accurate but the time zone display name is "Unknown Time Zone" and not the one that I have set. Here's what I've got: (I'm trying to set my time zone to MST, Mountain Standard Time). Also, there is a piece of code below that sets the privilege for my application to set the time zone, just assume that it works fine :-) Why doesn't the OS recognize the name of the time zone? What am I doing wrong? Thanks in advance.

     

    Code Snippet

     

    public class Time

    {

    #region DLL Imports

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

    private static extern int GetTimeZoneInformation(out TimeZoneInformation lpTimeZoneInformation);

     

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

    private static extern bool SetTimeZoneInformation(ref TimeZoneInformation lpTimeZoneInformation);

     

    [StructLayout(LayoutKind.Sequential)]

    public struct SYSTEMTIME

    {

    public short wYear;

    public short wMonth;

    public short wDayOfWeek;

    public short wDay;

    public short wHour;

    public short wMinute;

    public short wSecond;

    public short wMilliseconds;

    }

     

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

    public struct TimeZoneInformation

    {

    public int bias;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

    public string standardName;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

    public string daylightName;

    SYSTEMTIME standardDate;

    SYSTEMTIME daylightDate;

    public int standardBias;

    public int daylightBias;

    }

    #endregion

     

     

    public static TimeZone CurrentTimeZone

    {

    get { return TimeZone.CurrentTimeZone; }

    }

     

     

    public static bool SetTimeZone(TimeZoneInformation tzi)

    {

    ComputerManager.EnableToken("SeTimeZonePrivilege", Process.GetCurrentProcess().Handle);

    // set local system timezone

    return SetTimeZoneInformation(ref tzi);

    }

     

    public static TimeZoneCollection GetTimeZones()

    {

    //open key where all time zones are located in the registry

    RegistryKey timeZoneKeys = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones");

    //create a new hashtable which will store the name

    //of the timezone and the associate time zone information struct

    TimeZoneCollection zones = new TimeZoneCollection();

    //iterate through each time zone in the registry and add it to the hash table

    foreach (string zonekey in timeZoneKeys.GetSubKeyNames())

    {

    //get current time zone key

    RegistryKey individualZone = timeZoneKeys.OpenSubKey(zonekey);

    //create new TZI struct and populate it with values from key

    TimeZoneInformation TZI = new TimeZoneInformation();

    TZI.standardName = individualZone.GetValue("Dlt").ToString();

    TZI.daylightName = individualZone.GetValue("Display").ToString();

    //read binary TZI data, convert to byte array

    byte[] b = (byte[])individualZone.GetValue("TZI");

    TZI.bias = BitConverter.ToInt32(b, 0);

    //add the name and TZI struct to hash table

    zones.Add(TZI.daylightName, TZI);

    }

    return zones;

    }

    }

     

    static void Main(string[] args)

    {

    Time.TimeZoneInformation tzi = new Time.TimeZoneInformation();

    string name = string.Empty;

    foreach (string key in Time.GetTimeZones().Keys)

    {

    if (key.Contains("Mountain"))

    {

    name = key;

    }

    }

    tzi = (Time.TimeZoneInformation)Time.GetTimeZones()[name];

    Time.SetTimeZone(tzi);

     

    }

    Wednesday, March 26, 2008 5:28 AM

Answers

  • Thanks for the link...

     

     

    Turns out I was reading the wrong registry key value. I was reading "Dlt" and then populating TZI.standardname with that value when I should have been reading "Std". The mistake is on me. Thanks for your help and quick responses!

     

    Patrick

     

    Wednesday, March 26, 2008 6:17 AM

All replies

  • You must set every member of the TimeZoneInformation struct, or Windows will give you unexpected results.

    Hope This Helps,
    Sumit
    Wednesday, March 26, 2008 5:35 AM
  •  

    Ok,that was one thing I wondered about... I understood that I wasn't setting the 'daylightbias' and 'standardbias' but what values should I initialize them to? Am I not reading something from the registry key that I should be? As far as I can tell, I've read all that is there...

     

    Wednesday, March 26, 2008 6:04 AM
  • remarkpk,

    Take a look at the following: http://msdn2.microsoft.com/en-us/library/ms725481(VS.85).aspx

    Taken From MSDN

    Bias

    The current bias for local time translation on this computer, in minutes. The bias is the difference, in minutes, between Coordinated Universal Time (UTC) and local time. All translations between UTC and local time are based on the following formula:

    UTC = local time + bias

    This member is required.

    StandardName

    A description for standard time. For example, "EST" could indicate Eastern Standard Time. The string will be returned unchanged by the GetTimeZoneInformation function. This string can be empty.

    StandardDate

    A SYSTEMTIME structure that contains a date and local time when the transition from daylight saving time to standard time occurs on this operating system. If the time zone does not support daylight saving time or if the caller needs to disable daylight saving time, the wMonth member in the SYSTEMTIME structure must be zero. If this date is specified, the DaylightDate member of this structure must also be specified. Otherwise, the system assumes the time zone data is invalid and no changes will be applied.

    To select the correct day in the month, set the wYear member to zero, the wHour and wMinute members to the transition time, the wDayOfWeek member to the appropriate weekday, and the wDay member to indicate the occurrence of the day of the week within the month (1 to 5, where 5 indicates the final occurrence during the month if that day of the week does not occur 5 times).

    Using this notation, specify 02:00 on the first Sunday in April as follows: wHour = 2, wMonth = 4, wDayOfWeek = 0, wDay = 1. Specify 02:00 on the last Thursday in October as follows: wHour = 2, wMonth = 10, wDayOfWeek = 4, wDay = 5.

    If the wYear member is not zero, the transition date is absolute; it will only occur one time. Otherwise, it is a relative date that occurs yearly.

    StandardBias

    The bias value to be used during local time translations that occur during standard time. This member is ignored if a value for the StandardDate member is not supplied.

    This value is added to the value of the Bias member to form the bias used during standard time. In most time zones, the value of this member is zero.

    DaylightName

    A description for daylight saving time. For example, "PDT" could indicate Pacific Daylight Time. The string will be returned unchanged by the GetTimeZoneInformation function. This string can be empty.

    DaylightDate

    A SYSTEMTIME structure that contains a date and local time when the transition from standard time to daylight saving time occurs on this operating system. If the time zone does not support daylight saving time or if the caller needs to disable daylight saving time, the wMonth member in the SYSTEMTIME structure must be zero. If this date is specified, the StandardDate member in this structure must also be specified. Otherwise, the system assumes the time zone data is invalid and no changes will be applied.

    To select the correct day in the month, set the wYear member to zero, the wHour and wMinute members to the transition time, the wDayOfWeek member to the appropriate weekday, and the wDay member to indicate the occurrence of the day of the week within the month (1 to 5, where 5 indicates the final occurrence during the month if that day of the week does not occur 5 times).

    If the wYear member is not zero, the transition date is absolute; it will only occur one time. Otherwise, it is a relative date that occurs yearly.

    DaylightBias

    The bias value to be used during local time translations that occur during daylight saving time. This member is ignored if a value for the DaylightDate member is not supplied.

    This value is added to the value of the Bias member to form the bias used during daylight saving time. In most time zones, the value of this member is –60.

    The above mentions what and when you need for all the members. Some are ignored.

    Hope This Helps,
    Sumit
    Wednesday, March 26, 2008 6:09 AM
  • Thanks for the link...

     

     

    Turns out I was reading the wrong registry key value. I was reading "Dlt" and then populating TZI.standardname with that value when I should have been reading "Std". The mistake is on me. Thanks for your help and quick responses!

     

    Patrick

     

    Wednesday, March 26, 2008 6:17 AM
  • Hi remarkpk,

     

    Sorry for my poor english.

     

    I saw your code, a I copy to my project, because I have the same necessity as you.

    I change the "Dlt" to "Std", but some erros occurs, error "Expected class, delegate, enum, interface, or struct".

     

    I'm a beginner programmer so can you help me?

     

    Can you give me a full example? It's my first time using WIN APIs.

     

    Thank you very much.

    Regards

    Rafael

    Monday, April 7, 2008 1:12 PM
  •  

    Rafael,

     

    It sounds like you have something invalid at the namespace level like a variable declaration. Double check your opening and closing brackets { }. Also, post the code that you have currently and I'll be glad to help steer you in the right direction.

    Monday, April 7, 2008 7:50 PM
  • Hi remarkpk,

     

    The following code it's what I did and copied from yours.

    And the error from VS 2005 is "The type or namespace name 'TimeZoneCollection' could not be found (are you missing a using directive or an assembly reference?)".

    Thanks for your help.

     

    namespace test

    {

    public partial class Form1 : Form

    {

    private void Form1_Load(object sender, EventArgs e)

    {

    foreach (Time.TimeZoneInformation tzi in Time.GetTimeZones)

    {

    cboZones.Items.Add(tzi);

    }

    for (int i = 0; i < cboZones.Items.Count; i++)

    {

    if (Convert.ChangeType(cboZones.ItemsIdea, Time.TimeZoneInformation).standardName = Time.CurrentTimeZone.StandardName)

    {

    cboZones.SelectedIndex = i;

    break;

    }

    }

    }

    private void btnChangeTZI_Click(object sender, EventArgs e)

    {

    Time.SetTimeZone(Convert.ChangeType(cboZones.SelectedItem, Time.TimeZoneInformation));

    }

    }

    public class Time

    {

    #region DLL Imports

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

    private static extern int GetTimeZoneInformation(out TimeZoneInformation lpTimeZoneInformation);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

    private static extern bool SetTimeZoneInformation(ref TimeZoneInformation lpTimeZoneInformation);

    [StructLayout(LayoutKind.Sequential)]

    public struct SYSTEMTIME

    {

    public short wYear;

    public short wMonth;

    public short wDayOfWeek;

    public short wDay;

    public short wHour;

    public short wMinute;

    public short wSecond;

    public short wMilliseconds;

    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

    public struct TimeZoneInformation

    {

    public int bias;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

    public string standardName;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

    public string daylightName;

    SYSTEMTIME standardDate;

    SYSTEMTIME daylightDate;

    public int standardBias;

    public int daylightBias;

    }

    #endregion

    public static TimeZone CurrentTimeZone

    {

    get { return TimeZone.CurrentTimeZone; }

    }

     

    public static bool SetTimeZone(TimeZoneInformation tzi)

    {

    ComputerManager.EnableToken("SeTimeZonePrivilege", Process.GetCurrentProcess().Handle);

    // set local system timezone

    return SetTimeZoneInformation(ref tzi);

    }

    public static TimeZoneCollection GetTimeZones()

    {

    //open key where all time zones are located in the registry

    RegistryKey timeZoneKeys = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones");

     

    //create a new hashtable which will store the name

    //of the timezone and the associate time zone information struct

    TimeZoneCollection zones = new TimeZoneCollection();

    //iterate through each time zone in the registry and add it to the hash table

    foreach (string zonekey in timeZoneKeys.GetSubKeyNames())

    {

    //get current time zone key

    RegistryKey individualZone = timeZoneKeys.OpenSubKey(zonekey);

    //create new TZI struct and populate it with values from key

    TimeZoneInformation TZI = new TimeZoneInformation();

    TZI.standardName = individualZone.GetValue("Std").ToString();

    TZI.daylightName = individualZone.GetValue("Display").ToString();

    //read binary TZI data, convert to byte array

    byte[] b = (byte[])individualZone.GetValue("TZI");

    TZI.bias = BitConverter.ToInt32(b, 0);

    //add the name and TZI struct to hash table

    zones.Add(TZI.daylightName, TZI);

    }

    return zones;

    }

    }

    }

    Tuesday, April 8, 2008 1:33 PM
  •  

    Hello remarkpk,

    I tried to run your code and I am getting an error regarding

    TimeZoneCollection assembly reference. I do not find anywhere in the code that  you have posted a definition of TimeZoneCollection, could you post that?

     

    thanks

    Tuesday, April 8, 2008 10:16 PM
  •  

    Is there a way I can post the entire class somehow? I don't want to just copy and paste it here in this thread. TimeZoneCollection is just a class that inherits from Hashtable. I created it because each time you access the object in a hashtable, you have to cast it to the correct type and I didn't like my code to be full of casts. So, here is that class.

     

    Code Snippet

    /// <summary>

    /// Represents a hashtable containing TIME_ZONE_INFORMATION structures for each time

    /// zone in the registry where each struct can be accessed in the collection by specifying

    /// the standard name of the time zone.

    /// </summary>

    public class TimeZoneCollection : Hashtable

    {

    /// <summary>

    /// Creates a new instance of a TimeZoneCollection containing no elements

    /// </summary>

    public TimeZoneCollection() : base() {}

    /// <summary>

    /// Adds the specified values to the collection.

    /// </summary>

    /// <param name="standardName">The standard name of the time zone.</param>

    /// <param name="tzi">The TimeZoneInformation structure containing data corresponding to the standard timezone name.</param>

    public void Add(string standardName, TIME_ZONE_INFORMATION tzi)

    {

    base.Add(standardName, tzi);

    }

    /// <summary>

    /// Returns the TIME_ZONE_INFORMATION struct corresponding to the specified standard time zone name.

    /// </summary>

    /// <param name="name">The standard name of the time zone whose euqivalent TZI struct should be retrieved.</param>

    public TIME_ZONE_INFORMATION this[string name]

    {

    get

    {

    return (TIME_ZONE_INFORMATION)base[name];

    }

    set

    {

    base[name] = value;

    }

    }

    }

     

     

    I've made quite a few changes to the class so I dont know if the code you have will work. If I can send you the whole file, i'd be happy to.
    Wednesday, April 9, 2008 3:21 AM
  • I was wondering how you got the correct name (Ex: (GMT-07:00) Arizona) to display correctly in windows explorer. I know it involves your TimeZoneCollection : HashTable class but I can't figure out how you cast the name value into the TimeZoneInformation object. I can set the Time Zone correctly but the TZI key values in my registry all return the same bias after I use the bit converter. So for example: When I set the Time Zone to Mountain Standard Time, It gets Set to Arizona Time. It seems as if the TZI's are grouped by thier corresponding number. For example all of the TZI's for (GMT-07:00) return a bias of 420... Which is wrong for Mountain Time. Any thoughts on how to correct this? Any help would be appreciated.
    Wednesday, July 16, 2008 8:01 PM
  • Hi remarkpk,

    i want to apply settings to change timezone settings but the code that u have posted previously does not work on windows 7 can u please help me out?????

    Monday, September 27, 2010 7:56 AM
  • Hello,

    I Can change the time successfully, But i have one problem. In clock of windows 7 appears the follow message 

    "Your current time zone is not recognized. Please select a valid time zone using the link below."

    Any suggestion for valid my time zone when a change that by my application??

    Thanks for your help, and sorry for my bad english.

    Carlos Pereira

    • Proposed as answer by cmbpereira Wednesday, September 26, 2012 10:10 AM
    • Unproposed as answer by cmbpereira Wednesday, September 26, 2012 10:10 AM
    Friday, September 21, 2012 10:46 AM
  • When i use SetTimeZoneInformation function to set time zone i got similar result.

    So, i started looking how SetTimeZoneInformation affected registry and found out that this function do not change TimeZoneKeyName registry key. 

    I used SetDynamicTimeZoneInformation function instead of SetTimeZoneInformation.

    here is the little piece of code for Azerbaijan Standard Time :

     

    DYNAMIC_TIME_ZONE_INFORMATION tzi;

       DWORD dwRet;

    StringCchCopy(tzi.StandardName, 32, L

    "@tzres.dll,-449");

       StringCchCopy(tzi.TimeZoneKeyName, 32, L

    "Azerbaijan Standard Time");

       StringCchCopy(tzi.DaylightName, 32, L

    "@tzres.dll,-449");

    if( !SetDynamicTimeZoneInformation( &tzi ) )

       {

          printf(

    "STZI failed (%d)\n", GetLastError());

         

    return 0;

       }

    Wednesday, May 21, 2014 5:38 AM
  • Here is another approach to set timezone on Windows:

     //Set timezone
                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = @"tzutil.exe";
                startInfo.Arguments = @"/s ""Russian Standard Time""";
                Process.Start(startInfo);


    Dura lex, sed lex!

    Thursday, August 24, 2017 3:01 PM
  • Works perfectly. I'm developing the standalone windows app which will be installed in lot of Windows 10 PCs will the tzutil.exe file exists as part of Windows 10 ?
    Friday, June 7, 2019 11:02 PM