【问题标题】:How to compare DateTime values, taking into account timezone?考虑到时区,如何比较 DateTime 值?
【发布时间】:2015-09-22 02:27:41
【问题描述】:

我有两个DateTime 变量。每个都有一个存储在变量中的时区,因此当我 ToString 使用包含 zzz 的格式时,我会得到一个包含 +01:00 的字符串。

在设计时,我不知道时区是什么,我希望变量之间有不同的时区。

我想比较两个 DateTime 值,以便知道哪个是最近的。

例如,如果变量 A 是 2015-07-04T02:00:00+03:00,变量 B 是 2015-07-03T18:00:00-07:00,那么 B > A。

我用 C# 写什么来告诉我这个? (我宁愿不使用第三方库。)

(致 SO 问题结束狂热者:我已经使用 Google、MSDN 和 SO 进行了几个小时的调查,但我很困惑。我在 SO 上找不到与此非常相似的问题。我相信这个问题的答案会帮助他人。)

【问题讨论】:

  • DateTime 在 .NET 中是时区 awareness。在 Nodatime 中使用 ZonedDateTime
  • @SonerGönül 你的第一句话是什么意思?
  • @SonerGönül 我宁愿知道如何在没有第三方库的情况下做到这一点。
  • @SonerGönül 你写的 .NET 是时区感知,那么为什么要使用第三方库?

标签: c# datetime timezone


【解决方案1】:

你说:

我有两个 DateTime 变量。每个都有一个存储在变量中的时区,因此当我使用包含 zzz 格式的 ToString 时,我会得到一个包含 +01:00 的字符串。

这是一个常见的误解。 DateTime 没有存储在变量中的时区。它只有一个Kind 属性,其类型为DateTimeKind,可以是UtcLocalUnspecified

调用ToString 时,zzz 格式说明符使用Kind 属性来确定要显示的偏移量。

  • KindDateTimeKind.Utc 时,偏移量始终为+00:00

  • KindDateTimeKind.Local 时,偏移量是根据执行代码的计算机上的本地时区确定的。例如,我的计算机设置为美国太平洋时间,因此偏移量将是-08:00-07:00,具体取决于夏令时是否有效。

  • KindDateTimeKind.Unspecified 时,行为与Local 相同。请记住,其他方法以不同方式处理 Unspecified - 这只是 zzz 说明符的特定行为。

MSDN actually says:

因此,不建议将“zzz”格式说明符与DateTime 值一起使用。

回到你的问题:

在设计时,我不知道时区是什么,我希望变量之间有不同的时区。

那么你不能使用DateTime。您应该改用DateTimeOffset,因为它保留了特定的时区偏移量,而不是使用DateTimeKind

例如,如果变量 A 是 2015-07-04T02:00:00+03:00 而变量 B 是 2015-07-03T18:00:00-07:00 那么 B > A. 我写什么C# 告诉我这个?

DateTimeOffset a = DateTimeOffset.Parse("2015-07-04T02:00:00+03:00");
DateTimeOffset b = DateTimeOffset.Parse("2015-07-03T18:00:00-07:00");

bool result = b > a;  // true

另见:DateTime vs DatetimeOffset


此外

正如 Gustav 指出的那样,您可以只使用DateTime,只要在比较之前转换回通用时间即可。这得益于DateTime's hidden fourth state (more here)。在解析过程中正确设置了状态,并在调用ToUniversalTime 时将其考虑在内。然后比较具有有效的 UTC 时间来进行操作。

DateTime A = DateTime.Parse("2015-11-01T01:00:00-07:00");
DateTime B = DateTime.Parse("2015-11-01T01:00:00-08:00");

Console.WriteLine(A.ToUniversalTime().ToString("'A: 'yyyy'-'MM'-'dd hh:mm:ss"));
Console.WriteLine(B.ToUniversalTime().ToString("'B: 'yyyy'-'MM'-'dd hh:mm:ss"));
Console.WriteLine( B.ToUniversalTime() > A.ToUniversalTime() );
Console.WriteLine( B > A );

结果:

A: 2015-11-01 08:00:00
B: 2015-11-01 09:00:00
True
False

如果您的本地时区设置为太平洋时间,您将获得上述结果。但是,如果将其设置为其他值 - 您可能会在最后一个结果中获得 True,因为这些值可能已被解析为您所在时区的不同 local 时间,即使它们会与太平洋时区的本地时间相同

使用DateTimeOffset还是比较简单,转换次数少,不受当地时区影响。

【讨论】:

  • 感谢您提供如此全面的答案,以及对我最初相信的另一个答案的评论,就像我在 GMT+1 时一样。
【解决方案2】:

你试过了吗?

var A = DateTime.Parse("2015-07-04T02:00:00+03:00");
var B = DateTime.Parse("2015-07-03T18:00:00-07:00");

Console.WriteLine( B > A );

【讨论】:

  • 但为什么要用var 代替DateTime
  • 此代码似乎可以工作,但由于生成的 DateTime 值将被转换为 本地 时区,它可能会失败,具体取决于当地时区。
  • @Gustav - var 只是隐式类型的简写。见msdn for details
  • 怎么可能失败?两个时间都将转换为相同的时区。没有理由投反对票。
  • @Gustav - 我的错,我混淆了AB。 01:00-7 是 DST 时间,所以它在 01:00-8 之前。不过,关于您的代码,关键是您在比较之前调用ToUniversalTime。由于the hidden fourth state (more here),它可以工作。 > 运算符不使用 kind,因此它不会考虑该状态,但 ToUniversalTime 会。
猜你喜欢
  • 2019-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-16
  • 2013-09-01
  • 2023-03-03
  • 2021-06-15
  • 1970-01-01
相关资源
最近更新 更多