【问题标题】:Forcing a DateTime to be under a specific timezone, given only a DateTime with unspecified timezone仅给定具有未指定时区的 DateTime 强制 DateTime 在特定时区下
【发布时间】:2019-03-15 17:52:08
【问题描述】:

我有一个约会,比如“2016-10-20 20:34:60”。创建此日期时间时,我不确定如何指定此日期时间是根据服务器本地时区制作的。在这种情况下,它是“太平洋标准时间”。

我想将其作为默认文本和数据文本呈现。该数据文本将通过 javascript 用于将日期更改为用户的本地时间。

我是 C# 新手,我正在努力思考如何去做。给出的许多示例都使用 UTC 时间。我们根据服务器本地时间存储日期。

我想确保显示的默认文本是正确的,无论我们是否处于夏令时模式,它都应该及时反映当时的情况。

【问题讨论】:

  • 这应该会有所帮助:stackoverflow.com/questions/3323113/…
  • 顺便说一句,您可能希望考虑使用 UTC。 stackoverflow.com/questions/11537106/…
  • @MikeH,我希望他们将事物存储为 UTC。让一切变得更容易。但我无法控制。
  • @Sam - 仅仅因为存储了非 UTC 时间,并不意味着您在发送出去之前不能转换为 UTC。
  • @MattJohnson,我将时间作为 UTC 时间戳作为隐藏字段发送,这是我在 javascript 和 Date 对象中使用的。我只关心从数据库返回的日期,并确保将其设置为正确的时区,因为我看到 Kind 是未指定的。

标签: c# datetime timezone


【解决方案1】:

一般来说,您不应依赖服务器的本地时区。这是一个系统范围的设置,无需管理权限即可轻松更改。这样做会使您容易受到难以追踪的生产错误的影响,例如集群中的一台服务器的时区设置与另一台服务器不同。如果将服务器移动到其他位置(或云)并影响您的数据,也会出现问题。

服务器故意将其时区设置为 UTC 也很常见,因为它们的日志文件不会受到夏令时转换等因素的影响。

如果您仍然想断言DateTime 值反映了计算机的本地时区,您可以通过确保在.Kind 属性中设置DateTimeKind.Local 来做到这一点。这可以在构造函数参数中完成,或者在解析时使用DateTimeStyles.AssumeLocal,或者在现有值上使用DateTime.SpecifyKind。然后,您可以使用 .ToUniversalTime() 将其转换为 UTC,然后再将其发送给最终用户。

但是,我强烈建议您改用DateTimeOffset。与DateTime 不同,它将保留偏移量,并在大多数操作中考虑到它。如果您从 DateTimeDateTimeKind.Unspecified 构造 DateTimeOffset,它将默认为本地时区。同样,如果通过解析创建一个(DateTimeOffset.Parse.TryParse.ParseExact.TryParseExact等)如果输入字符串中没有偏移量,也会默认为本地时区。

然而 - 这些对象都不会以适当考虑转换的方式实际跟踪时区(例如当夏令时在 PST 和 PDT 之间移动太平洋时间时,反之亦然) .如果那是您正在寻找的东西 - 对不起,您对内置类型不走运。相反,您需要使用 Noda Time 开源库中的 ZonedDateTime 类。

另外,你说:

...此数据文本将通过 javascript 用于将日期更改为用户的本地时间。

这不是不可能的,但要让 JavaScript 将日期和时间转换为用户的本地时区是相当困难的,除非你也有偏移量。将DateTimeOffset 值序列化回浏览器会给您显示,但如果您要要求用户更改值,那么您必须以某种方式将其转换回来。

如果您只是简单地在浏览器和服务器之间来回传递 UTC 值,那就简单多了。然后,您可以在浏览器中将 UTC 转换为本地时间,反之亦然。 (至少对于日期+时间值。不要尝试转换仅日期值。)

【讨论】:

  • 是的。对不起。我的方法是在给定服务器本地时间(“显示”文本)的情况下提供一个默认值。基本上,我通过 C# 创建它。除此之外,我还将日期时间转换为 utc 日期(YM-DTH:M:S 偏移量)将 c# 中的时间戳转换为 utc 时间戳,然后将其设置为隐藏输入字段(“数据”值) .然后,我采用该“数据”值并创建一个新的 Date js 对象,然后使用它来创建适当的“显示”文本(假设它已解析。)。我应该更新我的问题,以更清楚地说明我的问题是什么。
【解决方案2】:

您可以通过

获取当前时区
TimeZoneInfo.Local

或者,您可以像这样获取当前偏移量:

DateTimeOffset.Now

您需要将相关信息与您的日期和时间一起存储在数据库中。

编辑根据下面的评论和https://docs.microsoft.com/en-us/dotnet/standard/datetime/ TimeZone.CurrentTimeZone 已被取代。请改用TimeZoneInfo.Local。已修改答案以反映这一点。

【讨论】:

  • TimeZone.CurrentTimeZone 不应使用。它已被TimeZoneInfo.Local 取代。
  • @MattJohnson 谢谢!
【解决方案3】:

你可以使用

    TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific SA Standard Time");

DateTime newDateTime = TimeZoneInfo.ConvertTime(existingDateTime, timeZoneInfo);

您可以找到更多信息和示例here 和所有时区here

【讨论】:

  • 这不会很“可扩展”,因为您总是需要定义时区。
  • ConvertTime simplay 是否只是更改“existingDateTime”的 DateTimeKind,保持相同的日期?这基本上就是我想要得到的。这样它就可以在给定的时间点显示该日期的正确偏移量。
  • 仅供参考 - "Pacific SA Standard Time" 适用于智利圣地亚哥。此外,请注意网页上硬编码的时区列表。他们随着世界的变化而变化。而是使用TimeZoneInfo.GetSystemTimeZones(),或在命令行上使用TZUtil.exe /L。谢谢。
猜你喜欢
  • 2018-11-24
  • 2013-04-03
  • 2017-11-23
  • 2013-03-02
  • 2011-11-06
  • 2019-07-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多