C# DateTime 不包含 TimeZone,但它以某种方式知道它以哪种方式被初始化。怎么可能?
Posted
技术标签:
【中文标题】C# DateTime 不包含 TimeZone,但它以某种方式知道它以哪种方式被初始化。怎么可能?【英文标题】:C# DateTime does not contain TimeZone yet it somehows know in which way it has been initialized. How it is possible? 【发布时间】:2022-01-19 15:40:19 【问题描述】:我正在阅读 https://***.com/a/6519330/1375882 并且我了解 DateTime 不包含时区。实际上,DateTime 没有 TimeZone 成员字段。然而有ToLocalTime()
和ToUniversalTime()
成员。例如。我正在 +2 时区计算机中测试我的代码,它给出了跟踪(例如,现在它在 +2 时区是16.12.2021 16:17:23
)并且代码给出:
DateTime tmpNow = DateTime.UtcNow;
//16.12.2021 14:17:23 - this if fine, DateTime is UTC
tmp = tmpNow.ToString();
//16.12.2021 16:17:23
tmp = tmpNow.ToLocalTime().ToString();
//16.12.2021 14:17:23 - this is fine, DateTime is UTC
tmp = tmpNow.ToUniversalTime().ToString();
DateTime tmpCustom = new DateTime(2021, 12, 16, 16, 9, 10);
//16.12.2021 16:09:10 - this is strange, I assume that DateTime(...) is aware that it is
// executed in +2 and that 16:09:10 is in +2 and therefore ToString should be 14:09:10
tmp = tmpCustom.ToString();
//16.12.2021 18:09:10 - this is strange, see previous
tmp = tmpCustom.ToLocalTime().ToString();
//16.12.2021 14:09:10 - complete loss of understanding. If initialization has been to 14:09:10 UTC
// as I expected, then ToLocalTime.ToString had to bee 16:09:10, but ToLocalTime()... was 18:09:10
// hence ToUniversalTime() definitely had to be 2 hours before - 16:09:10.
tmp = tmpCustom.ToUniversalTime().ToString();
所以,这真的很奇怪 - DateTime 以某种方式感知它是使用 UTC 初始化还是使用简单的日期时间数字组合进行初始化。如何解释 DateTime 代码行为以及这种对隐藏时区的依赖?
【问题讨论】:
这是因为 tmpCustom 是“未指定”。如果您在未指定的情况下调用 ToLocal,C# 假定开发人员最了解您并且时间实际上是通用的,因此它会继续进行,就好像它是“UTC 到本地”并添加 2 小时。同样,如果它是未指定的并且您调用 ToUniversal,它会假设您知道它是本地的,并需要 2 小时才能使其成为通用。您调用的方法是指定源类型和目标;如果未指定,您可以想象这些方法称为“IsActuallyLocalMakeItToUniversal”和“IsActuallyUniversalMakeItToLocal” 【参考方案1】:所有这些都在文档中,您只需要知道在哪里查找即可。这里相关的是the Kind
property。它是一个枚举:Local、Utc 或 Unspecified。
当为本地时,它采用当前文化的时区。见docs for the constructor you use:
Kind 属性被初始化为 DateTimeKind.Unspecified。
然后前往ToUniversalTime()
:
ToUniversalTime 方法返回的值由当前 DateTime 对象的 Kind 属性决定
[...]
未指定:假定当前的 DateTime 对象是本地时间,并且按照 Kind 是 Local 的方式执行转换。
因此,如果您将代码更改为 new DateTime(2021, 12, 16, 16, 9, 10, DateTimeKind.Local)
,则之后的方法将按预期工作 - 除了您声称您期望“14:09”在那里的评论之外。那不会发生。
【讨论】:
我猜你的意思是说如果 OP 会使用DateTimeKind.Utc
它会按预期工作。由于明确声明 DateTimeKind.Local
不应该有所作为,因为它将被隐含地未指定,它再次被视为本地,所以没有区别。
@Rand 实际上 Local 和 Utc 都很好。未指定不是。如果您使用 Local 类型在 DateTime 上调用 ToLocalTime,您将获得相同的日期和时间。与 Utc 类型的 ToUniversal 相同。
抱歉,但我不明白为什么 .ToString()
应该返回 14:09:10
,如果明确声明了 DateTimeKind.Local
。 (在我的机器和 dotnetfiddle 上进行了测试,我得到了16:09:10
,正如我所料)
@Rand 对于任何种类的类型,new DateTime(2021, 12, 16, 16, 09, 10, DateTimeKind.*).ToString()
不可能返回他们用 cmets 表示的 14:09
时间。 ToString()
会打印出 DateTime 的组成部分,Hour 是 16。以上是关于C# DateTime 不包含 TimeZone,但它以某种方式知道它以哪种方式被初始化。怎么可能?的主要内容,如果未能解决你的问题,请参考以下文章
django 1.4 timezone.now() 与 datetime.datetime.now()
`datetime.now(pytz timezone)` 啥时候失败?
日期时间、熊猫和时区问题:AttributeError:“datetime.timezone”对象没有属性“_utcoffset”
DateTime 对象上的不同 timezone_types