Answered by:
Changing Time Zone with C#... Hmmmmm

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{
#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 tablezones.Add(TZI.daylightName, TZI);
}
return zones;}
}
{
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);}
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
All replies
-
-
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...
-
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.
Hope This Helps,
Sumit -
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
-
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
-
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.
-
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.Items, 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; }}
{
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");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 tablezones.Add(TZI.daylightName, TZI);
}
return zones;}
}
}
-
-
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 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.
-
-
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
-
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;
}
-
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!
-