oynix

于无声处听惊雷,于无色处见繁花

DateTime的DateTimeKind参数

在DateTime的构造方法里,有个DateTimeKind类型的参数,在了解不同参数的区别后,可能会有一些新的理解。

DateTimeKind有3个枚举值,

1
2
3
4
5
6
7
8
9
public enum DateTimeKind  
{
/// <summary><para>The time represented is not specified as either local time or Coordinated Universal Time (UTC).</para></summary>
Unspecified,
/// <summary><para>The time represented is UTC.</para></summary>
Utc,
/// <summary><para>The time represented is local time.</para></summary>
Local,
}

一、指定不同Kind的区别

1. 时间戳

在使用DateTime做加减法时,会忽略后面的Kind参数,只计算前面时间戳的值,举个例子,

1
2
3
4
5
6
7
8
9
10
11
var local = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
var utc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var unspecified = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);

var span1 = (int) (local - utc).TotalSeconds;
var span2 = (int) (local - unspecified).TotalSeconds;
var span3 = (int) (utc - unspecified).TotalSeconds;

Debug.Log("span1:" + span1); // 输出:span1:0
Debug.Log("span2:" + span2); // 输出:span2:0
Debug.Log("span3:" + span3); // 输出:span3:0

不同时区的0点,如果都转换成UTC时间的0点,时间戳的值是不同的,但是不转换的前提下,直接做加减法,它们之间的差值均为0,说明忽略了后面的Kind参数。

2. 表现形式

表现形式会受到DateTimeKind的值的影响,同样举个例子,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var local = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
var utc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var unspecified = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);

// 以universal的格式输出,也就是UTC

Debug.Log("local:" + local.ToString("U"));
// local:Wednesday, December 31, 1969 4:00:00 PM

Debug.Log("utc:" + utc.ToString("U"));
// utc:Thursday, January 1, 1970 12:00:00 AM

Debug.Log("unspecified:" + unspecified.ToString("U"));
//unspecified:Wednesday, December 31, 1969 4:00:00 PM

local是本地机器的时区,我这里是东八区,比0时区快8个小时,所以东八区的1号0点,对应0时区的前一天下午4点。utc则即为0时区时间,unspecified使用的时区是本地机器时区,所以和local的是一样的。

3. 关于R格式的时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var local = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
var utc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var unspecified = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);

// RFC 1123格式输出

Debug.Log("local:" + local.ToString("R"));
// 输出:local:Thu, 01 Jan 1970 00:00:00 GMT

Debug.Log("utc:" + utc.ToString("R"));
// 输出:utc:Thu, 01 Jan 1970 00:00:00 GMT

Debug.Log("unspecified:" + unspecified.ToString("R"));
// 输出:unspecified:Thu, 01 Jan 1970 00:00:00 GMT

看到输出末尾的GMT,便知道这是格林威治时间,也就是0时区的时间。指定了不同Kind时区的时间,输出的时间却都是一样的,就像是后面的Kind参数没起作用一样。看到这些,感觉之前得出的结论被推翻,直到在官方文档上看到这么一句话,总算是打消了疑惑,

1
尽管 RFC 1123 标准将时间表示为协调世界时 (UTC),格式设置操作也不会修改正在格式化的 [DateTime]对象的值。

文档地址

意思就是,R格式是会忽略后面的Kind的值,只是将前半部分的时间进行格式化。

二、转换

1. Local和Utc

这两种类型的DateTime可以互相转换,

1
2
3
4
5
var local = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
var utc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

local.ToUniversalTime();
utc.ToLocalTime();

local调用ToLocalTime方法时,没有变化,utc同理

2. Unspecified类型

此类型没有指定时区,当调用ToUnivesalTime方法时,它的时区是Local;当调用ToLocalTime方法时,它的类型是Utc。

三、两个时间戳

DateTime有两个时间戳,一个是DateTime.Now,一个是DateTime.UtcNow,这两个的区别就是前面的时间不同,后面的Kind也不同,具体要看时区,比如东八区下午4点来说,

1
2
3
4
5
6
7
8
var utc = DateTime.UtcNow;
var now = DateTime.Now;

Debug.Log("local:" + local.ToString("G"));
// 输出: local:1/30/2024 4:00 PM

Debug.Log("utc:" + utc.ToString("G"));
// 输出: utc:1/30/2024 8:00 AM

当计算时间戳的时候,最好统一转换成UTC时间,然后再做加减法,

1
2
3
4
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var now = DateTime.UtcNow;
// var now = DateTime.Now.ToUniversalTime();
var timestamp = (int) (now - epoch).TotalSeconds;
------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2024/01/d426654a2b3e/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道