Datetime转Datetimeoffset引发的对timezone和offset的认识:时区不等于本地时间与UTC时间的偏移

//C#中DateTime类型转为DateTimeOffset

DateTime thisDate = new DateTime(2020, 4, 19, 0, 0, 0);

TimeSpan offset = new TimeSpan(-6, 0, 0);

DateTimeOffset thisTime = new DateTimeOffset(thisDate, offset);

 

看起来很简单是不是:DateTimeOffset = Datetime + 时区

但是不对,正确的说法是:DateTimeOffset = Datetime + offset

注:offset表示的是本地时间相对于UTC时间的偏移

What? Are you kidding me? 时区和offset不是一个意思么?

一开始我也是这么理解的,直到我认真的去看微软的官方文档(见文未),我发现其文档中有一个ShowPossibleTimeZones的方法,这个方法的作用是,传入一DateTimeOffset类型的方法,然后遍历所有的时区,找到与这个datetimeoffset中的offset相匹配的时区。

我困惑了:你offset都给我了,我还找什么时区啊?Offset=-6:00,那时区肯定也是-6:00啊。在中国这么理解是没错的,我们是+8区,然后offset也是+8,不会出现问题。

好吧,运行一下下面的代码,看看运行的结果,然后我会以我探索的过程告诉你时区和offset的区别。

推荐一个在线编译运行C#代码的网站:http://csharppad.com/

using System.Collections.ObjectModel;

ReadOnlyCollection<TimeZoneInfo> timeZones;

DateTime thisDate = new DateTime(2020, 4, 19, 0, 0, 0);

DateTimeOffset thisTime = new DateTimeOffset(thisDate, new

    TimeSpan(-6, 0, 0));

ShowPossibleTimeZones(thisTime);

 

//这个方法会打印与thisTime中的offset值一样的timezone

public static void ShowPossibleTimeZones(DateTimeOffset offsetTime) {

TimeSpan offset = offsetTime.Offset; ReadOnlyCollection

    <TimeZoneInfo> timeZones;

Console.WriteLine("{0} could belong to the following time

    zones:", offsetTime.ToString());

// Get all time zones defined on local system

timeZones = TimeZoneInfo.GetSystemTimeZones();

// Iterate time zones

foreach (TimeZoneInfo timeZone in timeZones) {

// Compare offset with offset for that date in that time zone

if (timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset)) { 
Console.WriteLine(" {0}", timeZone.DisplayName);}

}

Console.WriteLine();

}

运行结果如下:

4/19/2020 12:00:00 AM -06:00 could belong to the following time zones:

 (UTC-07:00) Chihuahua, La Paz, Mazatlan

 (UTC-07:00) Mountain Time (US & Canada)

 (UTC-06:00) Central America

 (UTC-06:00) Saskatchewan

 

是的,你没看错,offset = -6,打印的结果中却有-7的时区,这是怎么回事?

就是因为夏令时,世界上有很多国家和美国类似,有冬时制和夏时制之分。跟据所处的纬度不同,世界被分成了跨度为24小时(从-12到+13)的多个时区,在不采取夏时制的国家内,其时间的offset和时区是一致的,如我国。

在采取冬夏时制的国家内,其冬令时和时区是一致的,但是到了夏令时,因为本地时间被向前调整了一个小时,其与UTC时间的偏移就减少了一个小时,但是其所处的时区却是永久不变的,所以就造成了时区和偏移的不一致。下面以美国华盛顿的夏令时时间举个例子:

  • 华盛顿处于西五区(-5)
  • 2020年4月16日21:36:50是夏时制时间,因为夏时制时间被向前调整了1个小时,所以其与UTC时间的偏移为-4
  • 如果这时还有一个西五区的国家不采用夏时制,那么其时间应该时2020年4月16日20:36:50,比美国西五区慢一个小时,其与UTC时间的偏移为-5,与其所在的时区一致
  • 如果到了冬天,采用冬时制,那么美国华盛顿的时间就又被调了回来,offset就又与时区一致了

 

 

经过上面的例子,我方才明白,时区是不变的,但由于有些时区的国家采取了不同的计时制,因此在一年中不同的时期,其当地时间与UTC的偏移会与时区所表示的不一致,所以不能简单的用当地时间+时区来精确的表示时间,而是应该用Datetime + offset,而这个offset是可以根据时区和时间来推算出来的,即:Offset = 时区 + 夏令时调整时间

 

所以,精确的将某个数据库存的本地时间转为datetimeoffset你得这么做:

using System.Collections.ObjectModel;

ReadOnlyCollection<TimeZoneInfo> timeZones;

timeZones = TimeZoneInfo.GetSystemTimeZones();



// 取出数据库的时间

DateTime thisDate = new DateTime(2020, 4, 19, 0, 0, 0);



// 1 确定数据库存的时间的时区名字,实例化时区对象

//const string tzName = "Central Standard Time";

const string tzName = "China Standard Time";

TimeZoneInfo timeZone =  TimeZoneInfo.FindSystemTimeZoneById(tzName);



// 2 通过时区,找到时间的offset

TimeSpan offset = timeZone.GetUtcOffset(thisDate );



// 3 将时间转为DateTimeOffset

DateTimeOffset thisTime = new DateTimeOffset(thisDate, offset);



//打印

Console.WriteLine("{0} - {1}",timeZone.BaseUtcOffset, thisTime );



//遍历所有的timezone,打印该日期时间对应的offset

foreach (TimeZoneInfo timeZone in timeZones)

{

// 通过时区,找到时间的offset

TimeSpan offset = timeZone.GetUtcOffset(thisDate );

// 将时间转为DateTimeOffset

DateTimeOffset thisTime = new DateTimeOffset(thisDate, offset);

//打印

Console.WriteLine("{0} - {1}",timeZone.BaseUtcOffset, thisTime );

}

查询所有的时区:

// 查询打印所有的时区

using System.Collections.ObjectModel;

ReadOnlyCollection<TimeZoneInfo> timeZones;

timeZones = TimeZoneInfo.GetSystemTimeZones();

// Iterate time zones

foreach (TimeZoneInfo timeZone in timeZones)

{

Console.WriteLine("{0}: {1}",timeZone.Id,timeZone.DisplayName);

}

 

参考微软官方文档:https://docs.microsoft.com/en-us/dotnet/standard/datetime/choosing-between-datetime

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值