c#:时区、DateTime和DateTimeOffset

您所在的位置:网站首页 时区如何划分时间范围的 c#:时区、DateTime和DateTimeOffset

c#:时区、DateTime和DateTimeOffset

2024-07-17 21:57| 来源: 网络整理| 查看: 265

参考: https://blog.csdn.net/u010476739/article/details/118339679 https://www.cnblogs.com/wuxiaoqian726/archive/2011/03/19/1988931.html

先说下结论: 如果系统不考虑全球化的话,那么我们不用考虑时区的问题,因为我们可以认为中国境内的计算机全部用的是北京时间。

时区介绍

地球自转一圈是360度,共24小时,所以1小时15度,即:15度就是1个时区。 国际定义了本初子午线(0度经线)的位置在英国伦敦格林尼治天文台,自然世界时(UTC)也是指的格林尼治天文台(GMT)那里的时间。 认为北京处在东经120度线上,也就是东八区上,所以北京相比UTC时间有8个小时的时差。 由于地球自西向东转,所以北京比格林尼治最先接触阳光,自然就认为北京的时间比格林尼治快8个小时。 比如说: 2020-01-01 00:00:00 +00:00: 表示格林尼治此时正值午夜凌晨。 但用北京时间表示为 2020-01-01 00:08:00 +08:00,即:北京此时天已经亮了,人们正在准备上班。

为什么会有北京时间,全世界都用一个UTC时间不就行嘛? 世界那么大,各地都有自己的习惯,如果突然统一起来,真的不习惯。 比如说,按照UTC时间,我们应该午夜凌晨正在上班的路上,这听起来就很疯狂。。。

如果需要国际化,该如何使用时间

前提: http请求头中虽然有关于语言(中文简体、英文?)的信息,但是没有携带客户端时区的信息。 既然如此,我们就要在服务端统一一种时区,这样方便我们开发调试,因为是国人开发的应用,所以就用北京时间即可。 剩下的就是客户端了,因为服务端无法预料客户端的时区,所以为了方便统一开发,我们可以统一返回携带时区信息的北京时间,客户端接收后自行转换即可。 常用的携带时区的时间有下面两种格式:

2020-01-02T01:08:07Z 2020-01-02 09:08:07 +08:00 针对这两种格式的转换示例如下: //北京时间(东八区): 2020-01-02 09:08:07.123 var baseTime = new DateTimeOffset(2020, 01, 02, 09, 08, 07, 123, TimeSpan.FromHours(8)); //常规输出: 不考虑时区 var str = baseTime.ToString("yyyy-MM-dd hh:mm:ss");//2020-01-02 09:08:07 str = baseTime.ToString("yyyy-MM-dd hh:mm:ss.fff");//2020-01-02 09:08:07.123 //考虑时区,形式1 str = baseTime.ToUniversalTime().ToString("yyyy-MM-ddThh:mm:ssZ");//2020-01-02T01:08:07Z str = baseTime.ToUniversalTime().ToString("yyyy-MM-ddThh:mm:ss.fffZ");//2020-01-02T01:08:07.123Z //考虑时区,形式2 str = baseTime.ToString("yyyy-MM-dd HH:mm:ss zzz");//2020-01-02 09:08:07 +08:00 str = baseTime.ToString("yyyy-MM-dd HH:mm:ss.fff zzz");//2020-01-02 09:08:07.123 +08:00 //如果当前计算机设置的时区是北京时间(东八区)则输出为true,否则输出false var parse1 = DateTimeOffset.Parse("2020-01-02 09:08:07.123"); Console.WriteLine($"parse1==baseTime: {parse1 == baseTime}"); //输出true var parse2 = DateTimeOffset.Parse("2020-01-02T01:08:07.123Z"); Console.WriteLine($"parse2==baseTime: {parse2 == baseTime}"); //输出true var parse3 = DateTimeOffset.Parse("2020-01-02 09:08:07.123 +08:00"); Console.WriteLine($"parse3==baseTime: {parse3 == baseTime}");

那么c#中的DataTime和DataTimeOffset有什么差别? 相同点: 它们两个都存储了年、月、日、时、分、秒、毫秒信息。 区别点:DateTimeOffset中还存储了时区信息;而DateTime中未存储时区信息(虽然有个DateTimeKind,但它十个枚举,只有Unspecified、Utc、Local三个值且默认为Unspecified),它总是认为自己存储的时间的时区是当前计算机设置的时区;

以sqlserver为例看数据库中如何存储时间

sqlserver中的关于时间的类型如下:

date:3字节,表示范围:0001-01-01 到 9999-12-31 datetime:8字节,表示范围: 1753-01-01 00:00:00 到 9999-12-31 23:59:59 datetime2:6-8个字节,表示范围:0001-01-01 00:00:00 到 9999-12-31 23:59:59.9999999 smalldatetime:4个字节,表示范围:1900-01-01 00:00:00 到 2079-06-06 23:59:59 time:5个字节,表示范围: 00:00:00.0000000 到 23:59:59.9999999 datetimeoffset:10个字节,表示范围:0001-01-01 00:00:00 到 23:59:59.9999999,可表示时区

通过上面列举,我们可以发现,除非我们使用datetimeoffset,否则我们是无法保存时区信息的。 其实,对于服务器来说,数据库中存不存储时区并不是那么重要,只要保证web服务器、数据库服务器设置的时区一致即可!!! 推荐sqlserver中使用:datetime2。 另外:一般我们常设计列的类型为datetime,而不是datetime2。 其实这有个隐患:当程序中使用DateTime的默认值,即:0000-01-01时,我们无法插入到数据库中,报错如下:

“从 datetime2 数据类型到 datetime 数据类型的转换产生一个超出范围的值” 浏览器端如何显示时间

上面中建议后端返回的时间携带时区信息,也就是下面两种格式:

2020-01-02T01:08:07Z 2020-01-02 09:08:07 +08:00

那么前端应该怎么显示呢? 幸运的是,js脚本可以直接解析上面两种类型的时间,看下面代码:

new Date(Date.parse("2020-01-02 09:08:07 +08:00")).toDateString() "Thu Jan 02 2020" new Date(Date.parse("2020-01-02 09:08:07 +08:00")).toTimeString() "09:08:07 GMT+0800 (中国标准时间)" new Date(Date.parse("2020-01-02T01:08:07Z")).toLocaleDateString() "2020/1/2" new Date(Date.parse("2020-01-02T01:08:07Z")).toLocaleTimeString() "上午9:08:07" 关于夏令时

夏令时是个奇怪且别扭的东西,中国曾经实行过6年(1986年到1991年),之后便废除了。 那么什么是夏令时的呢? 因为夏季天亮的早、黑的晚,而人们还是以冬季的时间点作息,导致起的晚浪费了阳光,睡的晚浪费了蜡烛,所以就人为的在夏季到来时的某天夜里2点偷偷的将时间调快1小时,然后在夏季结束时的某天夜里2点偷偷的将时间调慢1小时。 上面的一听就很别扭,还有人为改时间的!!! 调整作息时间不就行了吗! 事实上,我们也仅在1986-1991年执行了6年而已,之后便废除了,现在我们都是夏季和冬季到来时调整作息时间的。 假如,我们使用夏令时会有什么影响呢?

夏季到来时,比如:1986年5月4日,在夜里凌晨2点你的表突然跳到了3点,这样你就少睡了一小时。。。 冬季到来时,比如:1986年9月14日,在夜里凌晨2点你的表突然跳到1点,这样你就多睡了一小时。。。 如果你恰好在这个时间段设置了定时任务,那么,你会发现,你的定时任务可能触发了两次,也可能没触发。。。 虽然我国废除了夏令时,但不代表其他国家也废除了,比如说美国目前就实行夏令时。 但,夏令时在全球已经明显不受欢迎了, 俄罗斯: 实行了很长时间,最终2014年通过杜马法案废除了。 西班牙:还在偷偷改时间。 美国:不仅偷偷改时间,而且各个州的时区不一样,所以重要会议一般都会标注时区。 全球有110多个国家在使用夏令时。 欧盟正在废除夏令时的路上。

另外,想查看哪些地区支持夏令时,可以在电脑的时区设置中发现:

TimeZoneInfo

TimeZoneInfo是一个关于时区的静态类,可以使得我们方便的操作与时区相关的信息 对于一个开放于全球的网站或服务,在时间上的显示是一个问题,因为各个国家都会有所谓的时差,好在 .Net提供了 TimeZoneInfo 类来解决这个问题。 TimeZoneInfo 类的方法可用于将一个时区的时间转换为其他任意时区的相应时间

静态成员 CreateCustomTimeZone()使用应用程序提供的数据创建自定义时区。 CreateCustomTimeZone 方法创建在本地系统注册表中未定义的时区。然后可使用 ToSerializedString 属性将时区对象的信息保存为字符串,该字符串可以以应用程序可访问的某种格式存储。使用 FromSerializedString 方法可将序列化字符串转换回 TimeZoneInfo 对象 FindSystemTimeZoneById()根据时区的标识符实例化在系统注册表中定义的时区。 FromSerializedString()反序列化一个字符串值,以重新创建先前已序列化的 TimeZoneInfo 对象。 GetSystemTimeZones()返回 TimeZoneInfo 对象的可枚举的 ReadOnlyCollection),它表示本地系统上可用的所有时区。 Local 属性:实例化表示本地时区的 TimeZoneInfo 对象。 Utc 属性:实例化表示 UTC 时区的 TimeZoneInfo 对象。 案例

TimeZoneInfo 的使用很简单,一开始利用 FindSystemTimeZoneById 找到对应的 TimeZoneInfo 对象,就可以利用该对象来转换时间。下列程序是示范如何将 UTC Time 转为东京的当地间时。

TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); Console.WriteLine(string.Format("UTC Time:{0}", time.ToString())); Console.WriteLine(string.Format("Tokyo Time:{0}", TimeZoneInfo.ConvertTime(time, TimeZoneInfo.Utc, timeZoneInfo)));

或许有人会问,该如何知道各个地区所对应的 id,其实利用 TimeZoneInfo.GetSystemtimeZones 就可以了。

var list = TimeZoneInfo.GetSystemTimeZones(); foreach (var timeZoneInfo in list) { Console.WriteLine(timeZoneInfo.DisplayName); Console.WriteLine(timeZoneInfo.Id); } 时区类型

Windows时区,在Windows平台实现,例:"China Standard Time" Olson(奥尔森)时区,在Linux,Mac,IOS,Andorid,JavaScript,Java,PHP和许多其他平台上广泛实现,例:"Asia/Shanghai" 两种类型可以互转,需要用Windows时区与国际时区的映射表来确认当前国际时区id 通过olson时区获取TimeZoneInfo:

/// /// Converts an Olson time zone ID to a Windows time zone ID. /// /// An Olson time zone ID. See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html. /// /// The TimeZoneInfo corresponding to the Olson time zone ID, /// or null if you passed in an invalid Olson time zone ID. /// /// /// See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html /// public static TimeZoneInfo OlsonTimeZoneToTimeZoneInfo(string olsonTimeZoneId) { var olsonWindowsTimes = new Dictionary() { { "Africa/Bangui", "W. Central Africa Standard Time" }, { "Africa/Cairo", "Egypt Standard Time" }, { "Africa/Casablanca", "Morocco Standard Time" }, { "Africa/Harare", "South Africa Standard Time" }, { "Africa/Johannesburg", "South Africa Standard Time" }, { "Africa/Lagos", "W. Central Africa Standard Time" }, { "Africa/Monrovia", "Greenwich Standard Time" }, { "Africa/Nairobi", "E. Africa Standard Time" }, { "Africa/Windhoek", "Namibia Standard Time" }, { "America/Anchorage", "Alaskan Standard Time" }, { "America/Argentina/San_Juan", "Argentina Standard Time" }, { "America/Asuncion", "Paraguay Standard Time" }, { "America/Bahia", "Bahia Standard Time" }, { "America/Bogota", "SA Pacific Standard Time" }, { "America/Buenos_Aires", "Argentina Standard Time" }, { "America/Caracas", "Venezuela Standard Time" }, { "America/Cayenne", "SA Eastern Standard Time" }, { "America/Chicago", "Central Standard Time" }, { "America/Chihuahua", "Mountain Standard Time (Mexico)" }, { "America/Cuiaba", "Central Brazilian Standard Time" }, { "America/Denver", "Mountain Standard Time" }, { "America/Fortaleza", "SA Eastern Standard Time" }, { "America/Godthab", "Greenland Standard Time" }, { "America/Guatemala", "Central America Standard Time" }, { "America/Halifax", "Atlantic Standard Time" }, { "America/Indianapolis", "US Eastern Standard Time" }, { "America/Indiana/Indianapolis", "US Eastern Standard Time" }, { "America/La_Paz", "SA Western Standard Time" }, { "America/Los_Angeles", "Pacific Standard Time" }, { "America/Mexico_City", "Mexico Standard Time" }, { "America/Montevideo", "Montevideo Standard Time" }, { "America/New_York", "Eastern Standard Time" }, { "America/Noronha", "UTC-02" }, { "America/Phoenix", "US Mountain Standard Time" }, { "America/Regina", "Canada Central Standard Time" }, { "America/Santa_Isabel", "Pacific Standard Time (Mexico)" }, { "America/Santiago", "Pacific SA Standard Time" }, { "America/Sao_Paulo", "E. South America Standard Time" }, { "America/St_Johns", "Newfoundland Standard Time" }, { "America/Tijuana", "Pacific Standard Time" }, { "Antarctica/McMurdo", "New Zealand Standard Time" }, { "Atlantic/South_Georgia", "UTC-02" }, { "Asia/Almaty", "Central Asia Standard Time" }, { "Asia/Amman", "Jordan Standard Time" }, { "Asia/Baghdad", "Arabic Standard Time" }, { "Asia/Baku", "Azerbaijan Standard Time" }, { "Asia/Bangkok", "SE Asia Standard Time" }, { "Asia/Beirut", "Middle East Standard Time" }, { "Asia/Calcutta", "India Standard Time" }, { "Asia/Colombo", "Sri Lanka Standard Time" }, { "Asia/Damascus", "Syria Standard Time" }, { "Asia/Dhaka", "Bangladesh Standard Time" }, { "Asia/Dubai", "Arabian Standard Time" }, { "Asia/Irkutsk", "North Asia East Standard Time" }, { "Asia/Jerusalem", "Israel Standard Time" }, { "Asia/Kabul", "Afghanistan Standard Time" }, { "Asia/Kamchatka", "Kamchatka Standard Time" }, { "Asia/Karachi", "Pakistan Standard Time" }, { "Asia/Katmandu", "Nepal Standard Time" }, { "Asia/Kolkata", "India Standard Time" }, { "Asia/Krasnoyarsk", "North Asia Standard Time" }, { "Asia/Kuala_Lumpur", "Singapore Standard Time" }, { "Asia/Kuwait", "Arab Standard Time" }, { "Asia/Magadan", "Magadan Standard Time" }, { "Asia/Muscat", "Arabian Standard Time" }, { "Asia/Novosibirsk", "N. Central Asia Standard Time" }, { "Asia/Oral", "West Asia Standard Time" }, { "Asia/Rangoon", "Myanmar Standard Time" }, { "Asia/Riyadh", "Arab Standard Time" }, { "Asia/Seoul", "Korea Standard Time" }, { "Asia/Shanghai", "China Standard Time" }, { "Asia/Singapore", "Singapore Standard Time" }, { "Asia/Taipei", "Taipei Standard Time" }, { "Asia/Tashkent", "West Asia Standard Time" }, { "Asia/Tbilisi", "Georgian Standard Time" }, { "Asia/Tehran", "Iran Standard Time" }, { "Asia/Tokyo", "Tokyo Standard Time" }, { "Asia/Ulaanbaatar", "Ulaanbaatar Standard Time" }, { "Asia/Vladivostok", "Vladivostok Standard Time" }, { "Asia/Yakutsk", "Yakutsk Standard Time" }, { "Asia/Yekaterinburg", "Ekaterinburg Standard Time" }, { "Asia/Yerevan", "Armenian Standard Time" }, { "Atlantic/Azores", "Azores Standard Time" }, { "Atlantic/Cape_Verde", "Cape Verde Standard Time" }, { "Atlantic/Reykjavik", "Greenwich Standard Time" }, { "Australia/Adelaide", "Cen. Australia Standard Time" }, { "Australia/Brisbane", "E. Australia Standard Time" }, { "Australia/Darwin", "AUS Central Standard Time" }, { "Australia/Hobart", "Tasmania Standard Time" }, { "Australia/Perth", "W. Australia Standard Time" }, { "Australia/Sydney", "AUS Eastern Standard Time" }, { "Etc/GMT", "UTC" }, { "Etc/GMT+11", "UTC-11" }, { "Etc/GMT+12", "Dateline Standard Time" }, { "Etc/GMT+2", "UTC-02" }, { "Etc/GMT-12", "UTC+12" }, { "Europe/Amsterdam", "W. Europe Standard Time" }, { "Europe/Athens", "GTB Standard Time" }, { "Europe/Belgrade", "Central Europe Standard Time" }, { "Europe/Berlin", "W. Europe Standard Time" }, { "Europe/Brussels", "Romance Standard Time" }, { "Europe/Budapest", "Central Europe Standard Time" }, { "Europe/Dublin", "GMT Standard Time" }, { "Europe/Helsinki", "FLE Standard Time" }, { "Europe/Istanbul", "GTB Standard Time" }, { "Europe/Kiev", "FLE Standard Time" }, { "Europe/London", "GMT Standard Time" }, { "Europe/Minsk", "E. Europe Standard Time" }, { "Europe/Moscow", "Russian Standard Time" }, { "Europe/Paris", "Romance Standard Time" }, { "Europe/Sarajevo", "Central European Standard Time" }, { "Europe/Warsaw", "Central European Standard Time" }, { "Indian/Mauritius", "Mauritius Standard Time" }, { "Pacific/Apia", "Samoa Standard Time" }, { "Pacific/Auckland", "New Zealand Standard Time" }, { "Pacific/Fiji", "Fiji Standard Time" }, { "Pacific/Guadalcanal", "Central Pacific Standard Time" }, { "Pacific/Guam", "West Pacific Standard Time" }, { "Pacific/Honolulu", "Hawaiian Standard Time" }, { "Pacific/Pago_Pago", "UTC-11" }, { "Pacific/Port_Moresby", "West Pacific Standard Time" }, { "Pacific/Tongatapu", "Tonga Standard Time" } }; var windowsTimeZoneId = default(string); var windowsTimeZone = default(TimeZoneInfo); if (olsonWindowsTimes.TryGetValue(olsonTimeZoneId, out windowsTimeZoneId)) { try { windowsTimeZone = TimeZoneInfo.FindSystemTimeZoneById(windowsTimeZoneId); } catch (TimeZoneNotFoundException) { } catch (InvalidTimeZoneException) { } } return windowsTimeZone; } 夏令时:

夏令时是指某个时区在春季将时间向前移动(通常为一小时),然后在秋季向后移动的时间段。 并非每个时区都会转换一小时。例如, Australia/Lord_Howe 时区仅偏移30分钟



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3