.Net DateTime 包含本地时间和夏令时

2023-12-08

恐怕我不太明白.Net 是如何实现的DateTime类处理本地时间戳(我住在德国,所以我的语言环境是 de_DE)。也许有人可以启发我一点;-)

The DateTime可以使用年、月等参数调用构造函数。另外还有一个DateTimeKind的价值Local, Utc, or Unspecified可以提供(=默认)。

Example:

DateTime a = new DateTime(2015, 03, 29, 02, 30, 00, DateTimeKind.Local);
DateTime b = new DateTime(2015, 03, 29, 02, 30, 00, DateTimeKind.Utc);
DateTime c = new DateTime(2015, 03, 29, 02, 30, 00, DateTimeKind.Unspecified);
DateTime d = new DateTime(2015, 03, 29, 02, 30, 00);

根据定义,值 c 和 d 相同。但如果我将所有内容相互比较,所有四个都是相同的。检查 VS 调试器中的对象表明Ticks值(和InternalTicks也)对所有人来说都是一样的。然而,内部dateData值不同,但显然被比较运算符忽略。

您可能已经注意到,我构建了今年 3 月 29 日凌晨 02:30 的值。我们的时区不存在这一时刻,因为切换到夏令时会跳过这一时刻。所以我预计会得到构造对象的异常a,但这并没有发生。

此外,DateTime有一个方法ToUniversalTime()它将被解释为本地时间的值转换为等效的 UTC 值。为了进行测试,我运行了一个循环,如下所示:

DateTime dt = new DateTime(2015, 03, 29, 01, 58, 00, DateTimeKind.Local);
DateTime dtEnd = new DateTime(2015, 03, 29, 03, 03, 00, DateTimeKind.Local);
while (dt < dtEnd)
{
    Log(" Localtime " + dt + " converted to UTC is " + dt.ToUniversalTime());
    dt = dt.AddMinutes(1);
}

结果是:

Localtime 29.03.2015 01:58:00 converted to UTC is 29.03.2015 00:58:00
Localtime 29.03.2015 01:59:00 converted to UTC is 29.03.2015 00:59:00
Localtime 29.03.2015 02:00:00 converted to UTC is 29.03.2015 01:00:00
Localtime 29.03.2015 02:01:00 converted to UTC is 29.03.2015 01:01:00
Localtime 29.03.2015 02:02:00 converted to UTC is 29.03.2015 01:02:00
...
Localtime 29.03.2015 02:58:00 converted to UTC is 29.03.2015 01:58:00
Localtime 29.03.2015 02:59:00 converted to UTC is 29.03.2015 01:59:00
Localtime 29.03.2015 03:00:00 converted to UTC is 29.03.2015 01:00:00
Localtime 29.03.2015 03:01:00 converted to UTC is 29.03.2015 01:01:00
Localtime 29.03.2015 03:02:00 converted to UTC is 29.03.2015 01:02:00

因此,.Net 将不存在的时间戳从本地时间转换为 UTC 没有问题。此外,向现有本地时间戳添加一分钟不是本地感知的,并且会给出不存在的时间戳。

因此,添加 64 个单分钟后,转换后的 UTC 时间戳仅比之前大 4 分钟。

换句话说,本地时间和 UTC 之间的转换应该是双射,在合法时间戳值之间给出一一对应的关系。

长话短说:我如何按照预期的方式正确处理这个问题(根据.Net)?拥有是什么感觉DateTimeKind如果没有正确考虑?我什至不敢问闰秒(23:59:60)是如何处理的;-)


迈克的回答很好。是的,DateTimeOffset几乎总是优先于DateTime(但不适合all场景),以及野田时间在很多方面都非常优越。不过,我可以添加更多详细信息来解决您的问题和意见。

First, MSDN有这样的说法:

UTC 时间适用于计算、比较以及在文件中存储日期和时间。本地时间适合显示在桌面应用程序的用户界面中。时区感知应用程序(例如许多 Web 应用程序)还需要与许多其他时区一起工作。

...

时区之间的转换操作(例如 UTC 与当地时间之间,或一个时区与另一个时区之间)会考虑夏令时,但算术和比较操作则不会。

由此我们可以得出结论,您提供的测试无效,因为它使用当地时间进行计算。它的有用之处仅在于它强调了 API 如何允许您打破其自己记录的指南。一般来说,由于该日期的本地时区不存在从 02:00 到 03:00 之前的时间,因此在现实世界中不太可能遇到,除非通过数学方式获得,例如通过每日循环获得未考虑 DST 的模式。

顺便说一句,野田时间解决这个问题的部分是ZoneLocalMappingResolver,在转换时使用LocalDateTime to a ZonedDateTime通过localDateTime.InZone方法。有一些合理的默认值,例如InZoneStrictly, or InZoneLeniently,但它并不只是像你所展示的那样默默地转移DateTime.

关于你的主张:

换句话说,本地时间和 UTC 之间的转换应该是双射,在合法时间戳值之间给出一一对应的关系。

事实上,这不是双射。 (经过维基百科上双射的定义,它不满足条件 3 或 4。)只有 UTC 到本地方向的转换才是函数。本地到 UTC 方向的转换在前向 DST 转换期间存在不连续性,并且在后退 DST 转换期间存在模糊性。您可能希望查看图表在 DST 标签 wiki 中.

回答您的具体问题:

我如何以预期的方式正确处理这个问题(根据.Net)?

DateTime dt = new DateTime(2015, 03, 29, 01, 58, 00, DateTimeKind.Local);
DateTime dtEnd = new DateTime(2015, 03, 29, 03, 03, 00, DateTimeKind.Local);

// I'm putting this here in case you want to work with a different time zone
TimeZoneInfo tz = TimeZoneInfo.Local; // you would change this variable here

// Create DateTimeOffset wrappers so the offset doesn't get lost
DateTimeOffset dto = new DateTimeOffset(dt, tz.GetUtcOffset(dt));
DateTimeOffset dtoEnd = new DateTimeOffset(dtEnd, tz.GetUtcOffset(dtEnd));

// Or, if you're only going to work with the local time zone, you can use
// this constructor, which assumes TimeZoneInfo.Local
//DateTimeOffset dto = new DateTimeOffset(dt);
//DateTimeOffset dtoEnd = new DateTimeOffset(dtEnd);

while (dto < dtoEnd)
{
    Log(" Localtime " + dto + " converted to UTC is " + dto.ToUniversalTime());

    // Math with DateTimeOffset is safe in instantaneous time,
    // but it might not leave you at the desired offset by local time.
    dto = dto.AddMinutes(1);

    // The offset might have changed in the local zone.
    // Adjust it by either of the following (with identical effect).
    dto = TimeZoneInfo.ConvertTime(dto, tz);
    //dto = dto.ToOffset(tz.GetUtcOffset(dto));
}

如果没有正确考虑,拥有 DateTimeKind 有何意义?

起初,DateTime没有一种。它的表现就好像种类是未指定的。DateTimeKind已在 .NET 2.0 中添加。

它涵盖的主要用例是防止双重转换。例如:

DateTime result = DateTime.UtcNow.ToUniversalTime();

or

DateTime result = DateTime.Now.ToLocalTime();

在 .NET 2.0 之前,这些都会导致错误数据,因为ToUniversalTime and ToLocalTime方法必须假设输入值是not转换。它会盲目地应用时区偏移,即使该值是already在所需的时区。

还有一些其他边缘情况,但这是主要的情况。另外,还有一个隐藏的fourthkind,它的使用使得以下内容在回退过渡期间仍能保持不明确的值。

DateTime now = DateTime.Now;
Assert.True(now.ToUniversalTime().ToLocalTime() == now);

乔恩·斯基特有关于此的一个很好的博客文章,您现在还可以在评论中看到它的讨论.NET 参考源 or in 新的 coreclr 源.

我什至不敢问闰秒(23:59:60)是如何处理的;-)

实际上.NET根本不支持闰秒,包括当前版本的Noda Time。它们也不被任何 Win32 API 支持,您也不会在 Windows 时钟上观察到闰秒。

在 Windows 中,闰秒通过 NTP 同步应用。时钟滴答作响,就好像闰秒没有发生一样,在下一次时钟同步期间,时间会被调整并被吸收。这是下一个闰秒的样子:

Real World              Windows
--------------------    --------------------
2015-06-30T23:59:58Z    2015-06-30T23:59:58Z
2015-06-30T23:59:59Z    2015-06-30T23:59:59Z
2015-06-30T23:59:60Z    2015-07-01T00:00:00Z   <-- one sec behind
2015-07-01T00:00:00Z    2015-07-01T00:00:01Z
2015-07-01T00:00:01Z    2015-07-01T00:00:02Z   
2015-07-01T00:00:02Z    2015-07-01T00:00:02Z   <-- NTP sync
2015-07-01T00:00:03Z    2015-07-01T00:00:03Z

我在午夜过后 2 秒显示同步,但实际上可能会晚得多。时钟同步始终发生,而不仅仅是闰秒。计算机的本地时钟不是超精密仪器 - 它会发生漂移,并且必须定期进行校正。您不能假设当前时间始终单调递增 - 它可以向前跳跃,也可以向后跳跃。

此外,上面的图表并不完全准确。我展示了几秒钟内的硬转变,但实际上,操作系统通常会通过在几秒的较长时间内(一次几毫秒)分散几个亚秒增量的变化效果来引入微小的修正。

在 API 级别,没有一个 API 支持超过 59 秒的字段。如果他们were要完全支持它,可能只是在解析过程中。

DateTime.Parse("2015-06-30T23:59:60Z")

这将引发异常。如果它were要工作,它必须处理额外的闰秒并返回前一秒(2015-06-30T23:59:59Z),或者下一秒(2015-07-01T00:00:00Z).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

.Net DateTime 包含本地时间和夏令时 的相关文章

  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • 欧洲中部时间 14 日 3 月 30 日星期五 00:00:00 至 日/月/年

    我尝试解析格式日期Fri Mar 30 00 00 00 CET 14至 日 月 年 这是我的代码 SimpleDateFormat formatter new SimpleDateFormat dd MM yyyy System out
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • 实例化类时重写虚拟方法

    我有一个带有一些虚函数的类 让我们假设这是其中之一 public class AClassWhatever protected virtual string DoAThingToAString string inputString retu
  • LINQ:使用 INNER JOIN、Group 和 SUM

    我正在尝试使用 LINQ 执行以下 SQL 最接近的是执行交叉联接和总和计算 我知道必须有更好的方法来编写它 所以我向堆栈团队寻求帮助 SELECT T1 Column1 T1 Column2 SUM T3 Column1 AS Amoun
  • 如何实例化 ODataQueryOptions

    我有一个工作 简化 ODataController用下面的方法 public class MyTypeController ODataController HttpGet EnableQuery ODataRoute myTypes pub
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 有没有办法让 doxygen 自动处理未记录的 C 代码?

    通常它会忽略未记录的 C 文件 但我想测试 Callgraph 功能 例如 您知道在不更改 C 文件的情况下解决此问题的方法吗 设置变量EXTRACT ALL YES在你的 Doxyfile 中
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使

随机推荐