Problem Setting the Time Zone with SetTimeZoneInformation

M

Mike

I'm writing an application for Windows XP Embedded. This application
requires that the user be able to change the time zone from within the
application. I'm trying to do this using SetTimeZoneInformation, but
it's not working correctly and I can't figure out why. I'm using Visual
C# to write the application.

The problem I'm having is that if I choose US Eastern Time (-5:00)
Eastern Time (US & Canada) then the code below winds up setting my Time
Zone to (-5:00) Bogota, Lima, Quito, even though I've managed to find
US Eastern Time in the registry and set the variables correctly. This
is a problem because although the time is correct I loose my daylight
savings time information.

Does anyone have any clue why this isn't working or how I could better
set the time zone?

Here's some code snippets from the code I'm using:

[DllImport("Kernel32.dll")]
private extern static Int64 GetTimeZoneInformation( ref
TIME_ZONE_INFORMATION lpTimeZoneInformation );

private struct SYSTEMTIME
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}

private unsafe struct TIME_ZONE_INFORMATION
{
public int Bias;
public fixed char StandardName[32];
public SYSTEMTIME StandardDate;
public int StandardBias;
public fixed char DaylightName[32];
public SYSTEMTIME DaylightDate;
public int DaylightBias;
}

private struct REGTIMEZONEINFORMATION
{
public int Bias;
public int StandardBias;
public int DaylightBias;
public SYSTEMTIME StandardDate;
public SYSTEMTIME DaylightDate;
}

public bool SetTimeZone(int index)
{
// Omitted (uses index to find the time zone in the registry so that I
can get the
// information about the time zone using the appropriate key's TZI
value

// We've found the right time zone, get the TZI data
object varValue = rkTZInfo.GetValue("TZI");
byte[] baData = varValue as byte[];
int iSize = baData.Length;
IntPtr buffer = Marshal.AllocHGlobal(iSize);
Marshal.Copy(baData, 0, buffer, iSize);
rtzi = (REGTIMEZONEINFORMATION)Marshal.PtrToStructure(buffer,
typeof(REGTIMEZONEINFORMATION));
Marshal.FreeHGlobal(buffer);

// Now fill out TIME_ZONE_INFORMATION with that data

TIME_ZONE_INFORMATION tZoneInfo = new TIME_ZONE_INFORMATION();
tZoneInfo.Bias = rtzi.Bias;
tZoneInfo.StandardBias = rtzi.StandardBias;
tZoneInfo.DaylightBias = rtzi.DaylightBias;
tZoneInfo.StandardDate = rtzi.StandardDate;
tZoneInfo.DaylightDate = rtzi.DaylightDate;

if (!SetTimeZoneInformation(ref tZoneInfo))
{
return (false);
}
}
 
M

Mike

Well it appears I've solved my own problem, however since I spent so
much time looking for a solution. I thought others might like to know,
so here are the above code snippets with the changes that made it all
work. Apparently, absolutely every field in TIME_ZONE_INFORMATION must
be filled in (especially the name) or it won't work.

Hopefully all this toil will help someone else.

<Code>

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private extern static bool SetTimeZoneInformation( ref
TIME_ZONE_INFORMATION lpTimeZoneInformation );

[StructLayoutAttribute(LayoutKind.Sequential)]
private struct SYSTEMTIME
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct TIME_ZONE_INFORMATION
{
public int Bias;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string StandardName;
public SYSTEMTIME StandardDate;
public int StandardBias;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DaylightName;
public SYSTEMTIME DaylightDate;
public int DaylightBias;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
private struct REGTZI
{
public int Bias;
public int StandardBias;
public int DaylightBias;
public SYSTEMTIME StandardDate;
public SYSTEMTIME DaylightDate;
}

public bool SetTimeZone(int index)
{
// Omitted (uses index to find the time zone in the registry so
that I
can get the
// information about the time zone using the appropriate key's
TZI
value

// We've found the right time zone, get the TZI data
object varValue = rkTZInfo.GetValue("TZI");
byte[] baData = varValue as byte[];
int iSize = baData.Length;
IntPtr buffer = Marshal.AllocHGlobal(iSize);
Marshal.Copy(baData, 0, buffer, iSize);
rtzi = (REGTZI)Marshal.PtrToStructure(buffer, typeof(REGTZI));
Marshal.FreeHGlobal(buffer);

// Now fill out TIME_ZONE_INFORMATION with that data
TIME_ZONE_INFORMATION tZoneInfo = new TIME_ZONE_INFORMATION();
tZoneInfo.Bias = rtzi.Bias;
tZoneInfo.StandardBias = rtzi.StandardBias;
tZoneInfo.DaylightBias = rtzi.DaylightBias;
tZoneInfo.StandardDate = rtzi.StandardDate;
tZoneInfo.DaylightDate = rtzi.DaylightDate;
tZoneInfo.StandardName = (string)rkTZInfo.GetValue("Std");
tZoneInfo.DaylightName = (string)rkTZInfo.GetValue("Dlt");

if (!SetTimeZoneInformation(ref tZoneInfo))
{
return (false);
}
}

</code>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top