項(xiàng)目中需要通過(guò)程序獲取和設(shè)置時(shí)區(qū),在網(wǎng)上搜了半天,這方面的資料很少,中文幾乎沒(méi)有完整的方案,只是有人提到用下面兩個(gè)API,具體怎么用,沒(méi)有找到完整的例子。英文資料也很少,找到一個(gè),思路沒(méi)問(wèn)題,但代碼有很大問(wèn)題。只能自己研究實(shí)現(xiàn),下面我就具體說(shuō)說(shuō)我是怎么做的。
獲取和設(shè)置時(shí)區(qū)信息需要用到下面兩個(gè)操作系統(tǒng) API
[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);
TimeZoneInformation 結(jié)構(gòu)如下:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TimeZoneInformation
{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;
}
SYSTEMTIME 結(jié)構(gòu)如下:
[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;
public SYSTEMTIME(byte[] buf, int index)
{wYear = BitConverter.ToInt16(buf, index);
index += 2;
wMonth = BitConverter.ToInt16(buf, index);
index += 2;
wDayOfWeek = BitConverter.ToInt16(buf, index);
index += 2;
wDay = BitConverter.ToInt16(buf, index);
index += 2;
wHour = BitConverter.ToInt16(buf, index);
index += 2;
wMinute = BitConverter.ToInt16(buf, index);
index += 2;
wSecond = BitConverter.ToInt16(buf, index);
index += 2;
wMilliseconds = BitConverter.ToInt16(buf, index);
}
}
獲取時(shí)區(qū)的顯示名
我們?cè)谠O(shè)置時(shí)區(qū)的界面上看到的名稱實(shí)際上是時(shí)區(qū)的顯示名,我們獲取和設(shè)置時(shí)區(qū)信息時(shí)一般也需要使用這個(gè)名字,而不是standardName 或者 daylightName. 那兩個(gè)名字只的是標(biāo)準(zhǔn)名和夏令時(shí)名稱,這兩個(gè)名字是操作系統(tǒng)自己使用的所有操作系統(tǒng)不管使用什么語(yǔ)言,這兩個(gè)名字都是一樣的。但顯示名,不同語(yǔ)言的操作系統(tǒng)是不一樣的。這個(gè)顯示名我們無(wú)法在 TimeZoneInformation 這個(gè)結(jié)構(gòu)中獲取,只能從注冊(cè)表中獲取。存放所有時(shí)區(qū)信息的注冊(cè)表位置在下面代碼所述位置
Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones");
這個(gè)注冊(cè)表項(xiàng)下面所有的子項(xiàng)中存放的就是操作系統(tǒng)中所有的時(shí)區(qū)信息。
我們需要把這些時(shí)區(qū)信息讀取到一個(gè)字典結(jié)構(gòu)中,這個(gè)字典的鍵是顯示名,值是時(shí)區(qū)信息。代碼如下:
/// <summary> /// Get all time zone informations /// </summary> /// <returns></returns>private static TimeZoneCollection GetTimeZones()
{ lock (_SyncRoot) {if (_Zones != null)
{ return _Zones;}
//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 _Zones = new TimeZoneCollection(); //iterate through each time zone in the registry and add it to the hash tableforeach (string zonekey in timeZoneKeys.GetSubKeyNames())
{ //get current time zone keyRegistryKey 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();string displayName = individualZone.GetValue("Display").ToString();
TZI.daylightName = individualZone.GetValue("Dlt").ToString(); //read binary TZI data, convert to byte arraybyte[] b = (byte[])individualZone.GetValue("TZI");
TZI.bias = BitConverter.ToInt32(b, 0);
TZI.standardBias = BitConverter.ToInt32(b, 4);
TZI.daylightBias = BitConverter.ToInt32(b, 8);
TZI.standardDate = new SYSTEMTIME(b, 12); TZI.daylightDate = new SYSTEMTIME(b, 28); //Marshal.PtrToStructure( //add the name and TZI struct to hash table_Zones.Add(displayName, TZI);
}
return _Zones;}
}
有了這個(gè)字典后,我們就可以通過(guò)顯示名來(lái)獲取時(shí)區(qū)信息了。
/// <summary> /// Get the Time zone by display name /// </summary> /// <param name="displayName">part of display name</param> /// <param name="wholeDisplayName">whole display name</param> /// <returns>time zone</returns>public static TimeZoneInformation GetTimeZone(string displayName, out string wholeDisplayName)
{TimeZoneCollection tzc = TimeZone.GetTimeZones();
foreach (string key in tzc.Keys)
{ if (key.IndexOf(displayName, 0, StringComparison.CurrentCultureIgnoreCase) >= 0) {wholeDisplayName = key;
return tzc[key];}
}
throw new Exception(string.Format("Can't find the display name : {0}", displayName));
}
上面這個(gè)函數(shù)輸入時(shí)區(qū)顯示名的一部分,然后獲取和這部分時(shí)區(qū)信息匹配的第一個(gè)時(shí)區(qū)信息。并返回這個(gè)時(shí)區(qū)完整的顯示名。
調(diào)用示例
OS.TimeZone.TimeZoneInformation tzi = TimeZone.GetTimeZone("Sydney", out displayName);
Console.WriteLine(displayName);
結(jié)果:(GMT+10:00) Canberra, Melbourne, Sydney
注意:如果是中文操作系統(tǒng),這里應(yīng)該輸入 “悉尼”
我們還可以獲取當(dāng)前的時(shí)區(qū)名
/// <summary> /// Get current time zone display name /// </summary> /// <returns></returns>public static string GetCurrentTimeZoneDisplayName()
{TimeZoneInformation tzi;
GetTimeZoneInformation(out tzi);TimeZoneCollection tzc = TimeZone.GetTimeZones();
foreach (string displayName in tzc.Keys)
{TimeZoneInformation tz = tzc[displayName];
if (tz.standardName.Equals(tzi.standardName, StringComparison.CurrentCultureIgnoreCase)) { return displayName;}
}
throw new Exception(string.Format("Can't find the display name of {0}", tzi.standardName));
}
我們還可以通過(guò)時(shí)區(qū)名來(lái)設(shè)置時(shí)區(qū)
/// <summary> /// set time zone by display name /// </summary> /// <param name="displayName">part of display name</param> /// <param name="wholeDisplayName">whole display name</param> /// <returns></returns>public static bool SetTimeZone(string displayName, out string wholeDisplayName)
{ //ComputerManager.EnableToken("SeTimeZonePrivilege", Process.GetCurrentProcess().Handle); // set local system timezone TimeZoneInformation tzi = GetTimeZone(displayName, out wholeDisplayName);return SetTimeZoneInformation(ref tzi);
}
調(diào)用示例:
OS.TimeZone.SetTimeZone("Sydney", out displayName)
上面代碼將時(shí)區(qū)設(shè)置為悉尼時(shí)間。
注意:如果是中文操作系統(tǒng),這里應(yīng)該輸入 “悉尼”
下面給出完整代碼
using System;using System.Collections.Generic;using System.Text;using System.Runtime.InteropServices;using System.Diagnostics;using Microsoft.Win32;namespace OS{using TimeZoneCollection = System.Collections.Generic.Dictionary<string, TimeZone.TimeZoneInformation>;
public class TimeZone
{ #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;
public SYSTEMTIME(byte[] buf, int index)
{wYear = BitConverter.ToInt16(buf, index);
index += 2;
wMonth = BitConverter.ToInt16(buf, index);
index += 2;
wDayOfWeek = BitConverter.ToInt16(buf, index);
index += 2;
wDay = BitConverter.ToInt16(buf, index);
index += 2;
wHour = BitConverter.ToInt16(buf, index);
index += 2;
wMinute = BitConverter.ToInt16(buf, index);
index += 2;
wSecond = BitConverter.ToInt16(buf, index);
index += 2;
wMilliseconds = BitConverter.ToInt16(buf, index);
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TimeZoneInformation
{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;
}
#endregionstatic object _SyncRoot = new object();
static TimeZoneCollection _Zones = null;
/// <summary> /// Get all time zone informations /// </summary> /// <returns></returns>private static TimeZoneCollection GetTimeZones()
{ lock (_SyncRoot) {if (_Zones != null)
{ return _Zones;}
//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 _Zones = new TimeZoneCollection(); //iterate through each time zone in the registry and add it to the hash tableforeach (string zonekey in timeZoneKeys.GetSubKeyNames())
{ //get current time zone keyRegistryKey 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();string displayName = individualZone.GetValue("Display").ToString();
TZI.daylightName = individualZone.GetValue("Dlt").ToString(); //read binary TZI data, convert to byte arraybyte[] b = (byte[])individualZone.GetValue("TZI");
TZI.bias = BitConverter.ToInt32(b, 0);
TZI.standardBias = BitConverter.ToInt32(b, 4);
TZI.daylightBias = BitConverter.ToInt32(b, 8);
TZI.standardDate = new SYSTEMTIME(b, 12); TZI.daylightDate = new SYSTEMTIME(b, 28); //Marshal.PtrToStructure( //add the name and TZI struct to hash table_Zones.Add(displayName, TZI);
}
return _Zones;}
}
/// <summary> /// Get the Time zone by display name /// </summary> /// <param name="displayName">part of display name</param> /// <param name="wholeDisplayName">whole display name</param> /// <returns>time zone</returns>public static TimeZoneInformation GetTimeZone(string displayName, out string wholeDisplayName)
{TimeZoneCollection tzc = TimeZone.GetTimeZones();
foreach (string key in tzc.Keys)
{ if (key.IndexOf(displayName, 0, StringComparison.CurrentCultureIgnoreCase) >= 0) {wholeDisplayName = key;
return tzc[key];}
}
throw new Exception(string.Format("Can't find the display name : {0}", displayName));
}
/// <summary> /// Get current time zone /// </summary> /// <returns></returns>public static TimeZoneInformation GetCurrentTimeZone()
{TimeZoneInformation tzi;
GetTimeZoneInformation(out tzi); return tzi;}
/// <summary> /// Get current time zone display name /// </summary> /// <returns></returns>public static string GetCurrentTimeZoneDisplayName()
{TimeZoneInformation tzi;
GetTimeZoneInformation(out tzi);TimeZoneCollection tzc = TimeZone.GetTimeZones();
foreach (string displayName in tzc.Keys)
{TimeZoneInformation tz = tzc[displayName];
if (tz.standardName.Equals(tzi.standardName, StringComparison.CurrentCultureIgnoreCase)) { return displayName;}
}
throw new Exception(string.Format("Can't find the display name of {0}", tzi.standardName));
}
/// <summary> /// Set time zone /// </summary> /// <param name="tzi"></param> /// <returns></returns>public static bool SetTimeZone(TimeZoneInformation tzi)
{ //ComputerManager.EnableToken("SeTimeZonePrivilege", Process.GetCurrentProcess().Handle); // set local system timezonereturn SetTimeZoneInformation(ref tzi);
}
/// <summary> /// set time zone by display name /// </summary> /// <param name="displayName">part of display name</param> /// <param name="wholeDisplayName">whole display name</param> /// <returns></returns>public static bool SetTimeZone(string displayName, out string wholeDisplayName)
{ //ComputerManager.EnableToken("SeTimeZonePrivilege", Process.GetCurrentProcess().Handle); // set local system timezone TimeZoneInformation tzi = GetTimeZone(displayName, out wholeDisplayName);return SetTimeZoneInformation(ref tzi);
}
}
}
浙公網(wǎng)安備 33010602011771號(hào)