在.Net 3.5下有一个TimeZoneInfo类,可以很方便的转换时区和进行时间转换.但是在.Net 2.0下,只能对当前服务器时区进行处理,十分不方便.特别系统是世界范围使用的,更需要考虑当地时区特别是夏令时的问题,不然时间就会错乱.如何解决这个问题,就要通过自己手动处理了.
其实Windows的时区信息都存放在Windows注册表的"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"下.只要读取相关信息出来.就能实现和TimeZoneInfo相同的功能.下边我们就通过一个小demo.读取世界时区信息,计算时区偏移量和夏令时偏移量.并根据用户选择的时区和输入时间,判断该时间是否属于该时区的夏令时范围.
首先,我们需要创建两个Struct来记录相关信息,一个是SytemTime,一个TimeZoneInformation.代码如下:
SystemTime Struct [StructLayout(LayoutKind.Sequential)] 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; public void SetInfo(byte[] info) { if (info.Length != Marshal.SizeOf(this)) { throw new ArgumentException("Information size is incorrect", "info"); } else { this.wYear = BitConverter.ToUInt16(info, 0); this.wMonth = BitConverter.ToUInt16(info, 2); this.wDayOfWeek = BitConverter.ToUInt16(info, 4); this.wDay = BitConverter.ToUInt16(info, 6); this.wHour = BitConverter.ToUInt16(info, 8); this.wMinute = BitConverter.ToUInt16(info, 10); this.wSecond = BitConverter.ToUInt16(info, 12); this.wMilliseconds = BitConverter.ToUInt16(info, 14); } } public override bool Equals(object obj) { if (this.GetType() == obj.GetType()) { try { SYSTEMTIME objSt = (SYSTEMTIME)obj; if (this.wYear != objSt.wYear || this.wMonth != objSt.wMonth || this.wDayOfWeek != objSt.wDayOfWeek || this.wDay != objSt.wDay || this.wHour != objSt.wHour || this.wMinute != objSt.wMinute || this.wSecond != objSt.wSecond || this.wMilliseconds != objSt.wMilliseconds) return false; else return true; } catch { return false; } } else return false; } public override int GetHashCode() { return base.GetHashCode(); } }
TimeZoneInformation Struct [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 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; public void SetBytes(byte[] info) { if (info.Length != 44) throw new ArgumentException("Information size is incorrect", "info"); else { this.bias = BitConverter.ToInt32(info, 0); this.standardBias = BitConverter.ToInt32(info, 4); this.daylightBias = BitConverter.ToInt32(info, 8); byte[] helper = new byte[16]; Array.Copy(info, 12, helper, 0, 16); this.standardDate.SetInfo(helper); Array.Copy(info, 28, helper, 0, 16); this.daylightDate.SetInfo(helper); } } public override bool Equals(object obj) { if (this.GetType() != obj.GetType()) { try { TimeZoneInformation objTzi = (TimeZoneInformation)obj; if (this.bias != objTzi.bias || this.daylightBias != objTzi.daylightBias || this.daylightName != objTzi.daylightName || this.standardBias != objTzi.standardBias || this.standardName != objTzi.standardName || !this.daylightDate.Equals(objTzi.daylightDate) || !this.standardDate.Equals(objTzi.standardDate) ) return false; else return true; } catch { return false; } } else return false; } public override int GetHashCode() { return base.GetHashCode(); } }
定义好相关Structs后,我们就可以读取注册表了.先定义几个读取注册表的方法:
RegistryKey Code private static RegistryKey GetTimeZoneRegistryKey(){ RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones", false); if (key == null) throw new KeyNotFoundException(@"Cannot find the windows registry key (Time Zone)."); else return key;}private static RegistryKey GetTimeZoneRegistrySubKey(string zoneId){ RegistryKey key = GetTimeZoneRegistryKey(); RegistryKey subKey = key.OpenSubKey(zoneId, false); if (subKey == null) throw new Exception("Unknown time zone."); else return subKey;}private static RegistryKey GetTimeZoneRegistryDynamicSubKey(TimeZoneInfo tzi){ RegistryKey subKey = GetTimeZoneRegistrySubKey(tzi._id); return subKey.OpenSubKey("Dynamic DST", false);}
下边我们开始读取注册表各个TimeZone信息
TimeZones Code public static TimeZoneInfo[] GetTimeZones(){ List<TimeZoneInfo> tzInfos = new List<TimeZoneInfo>(); RegistryKey key = GetTimeZoneRegistryKey(); foreach (string zoneName in key.GetSubKeyNames()) { TimeZoneInfo tzi = new TimeZoneInfo(); tzi._id = zoneName; tzi.SetValues(); tzInfos.Add(tzi); } TimeZoneInfo.Sort(tzInfos); return tzInfos.ToArray();}
可以看到上述代码是循环读取注册表里面的信息,通过SetVales方法放到一个List:
SetValues private void SetValues(){ RegistryKey subKey = GetTimeZoneRegistrySubKey(this._id); this._displayName = subKey.GetValue("Display").ToString(); this._tzi.daylightName = subKey.GetValue("Dlt").ToString(); this._tzi.standardName = subKey.GetValue("Std").ToString(); this._tzi.SetBytes(subKey.GetValue("Tzi") as byte[]);}
通过简单的读取信息填入TimeZoneInfo List,在页面级别我们就可以简单用下面的方法来显示给用户选择:
UI1 TimeZoneInfo[] TimeZones = TimeZoneInfo.GetTimeZones();this.drpList.DataSource = TimeZones;this.drpList.DataTextField = "DisplayName";this.drpList.DataValueField = "Id";this.drpList.DataBind();
当用选择了某一个时区,我们就可以根据用户选择的时区和输入的日期显示相关时区信息:
UI2 if (tzi.DisplayName == this.drpList.SelectedItem.Text){ DateTime dtDate = DateTime.Parse(this.txtDate.Text.Trim()); this.lblInfo.Text += string.Format("<br />时区ID: {0} ", tzi.Id); this.lblInfo.Text += string.Format("<br />显示名称: {0} ", tzi.DisplayName); this.lblInfo.Text += string.Format("<br />标准名称: {0} ", tzi.StandardName); this.lblInfo.Text += string.Format("<br /><br />当前时间是否夏令时: {0} ", tzi.IsDaylightSavingTime(dtDate).ToString()); this.lblInfo.Text += string.Format("<br />夏令时名称: {0} ", tzi.DaylightName(dtDate)); this.lblInfo.Text += string.Format("<br />基本偏移量: {0} ", tzi.StandardUtcOffset.ToString()); this.lblInfo.Text += string.Format("<br />当前偏移量: {0} ", tzi.GetCurrentUtcOffset(dtDate).ToString()); DaylightTime dt = tzi.GetDaylightChanges(dtDate.Year); this.lblInfo.Text += string.Format("<br />夏令时开始时间: {0} ", dt.Start.ToString("yyyy-MM-dd HH:mm:ss")); this.lblInfo.Text += string.Format("<br />夏令时结束时间: {0} ", dt.End.ToString("yyyy-MM-dd HH:mm:ss")); this.lblInfo.Text += string.Format("<br />夏令时增量: {0} ", dt.Delta.ToString());}
更详细的东西就不废话了.附上完整的Demo给大家看吧:
下载Demo点击这里
转载于:https://www.cnblogs.com/KenBlove/archive/2008/12/18/1357493.html
相关资源:时区及夏令时检测(C#源码)