我将所有 DateTime 字段存储为 UTC 时间。当用户请求网页时,我想采用他的首选本地时区(而不是服务器计算机的本地时区)并自动将所有 Web 表单中的所有日期时间字段显示为本地日期。
当然,我可以在每种表单中的每个 DateTime.ToString() 调用上应用转换或实现一些辅助实用程序,但这是一项耗时的任务,而且还有一些 3rd 方组件很难使用自定义 DateTime 显示模板进行配置。
本质上,我想让 DateTime 类的行为如下:
from this moment on for this web request,
whenever some code calls DateTime.ToString(), convert it to the local time
using the timezone offset given at the very beginning of the web request,
but if possible, please keep .NET core library DateTime.ToString() calls intact
(I don't want to mess up event logging timestamps etc.)
有什么办法可以做到吗?
顺便说一句,如果重要的话,我正在使用 ASP.NET MVC 4。
您不能直接按照您的要求进行操作,但我会建议一些替代方案。正如尼古拉斯指出的,HTTP 中没有任何内容可以直接为您提供时区。
Option 1
首先,确定您要使用哪种类型的时区数据。有两种不同的类型可用,您可以使用 Microsoft 时区访问TimeZoneInfo
类,或世界其他地区使用的 IANA/Olson 时区。在这里阅读更多信息。我的建议是后者,使用提供的实现NodaTime.
-
然后确定您要转换到的时区。您应该允许您的用户在某处设置来选择他们的时区。
您可能会显示一个下拉列表来选择多个时区之一,或者您可能会执行一些更有用的操作,例如显示世界地图,他们可以单击以选择他们的时区。有几个库可以在 Javascript 中执行此操作,但我最喜欢的是this one.
您可能想要猜测要使用的默认时区,以便在他们从列表(或地图)中进行选择之前您可以尽可能准确。有一个很棒的图书馆叫做js时区检测。它将询问浏览器的时钟并对其可能所在的时区做出最佳猜测。这是相当不错的,但仍然只是一个猜测。不要盲目地使用它——但一定要用它来确定一个起点。Update您现在也可以这样做moment.tz.guess()
, 在里面时刻时区moment.js 的组件。
现在您知道了用户的时区,您可以使用该值来转换您的 UTCDateTime
值到该本地时区。不幸的是,您无法在线程上设置任何内容来执行此操作。当您更改系统时区时,它对于所有进程和线程都是全局的。所以你别无选择,只能将时区传递到你发回的每个地方。 (我相信这是你的主要问题。)看到这个almost在此重复。
在将其转换为字符串之前,您还需要知道用户的区域设置(可以从请求.UserLanguages价值)。您可以将其分配给当前线程,也可以将其作为参数传递给DateTime.ToString()
方法。这不会进行任何时区转换 - 它只是确保数字位于正确的位置,使用正确的分隔符以及工作日或月份名称的适当语言。
Option 2
Don't将其转换为服务器上的本地时间。
-
既然您说您正在使用 UTC 值,请确保它们.Kind
财产是Utc
。您可能应该在从数据库加载时执行此操作,但如果必须,您可以手动执行此操作:
myDateTime = DateTime.SpecifyKind(myDateTime, DateTimeKind.Utc);
-
将其作为纯 UTC 以 ISO8601 等不变格式发送回浏览器。换句话说:
myDateTime.ToString("o"); // example: "2013-05-02T21:01:26.0828604Z"
-
在浏览器上使用一些 JavaScript 将其解析为 UTC。它将自动获取浏览器的本地时间设置。一种方法是使用内置的Date
JavaScript 中的对象,如下所示:
var dt = new Date('2013-05-02T21:01:26.0828604Z');
但是,这仅适用于支持 ISO-8601 格式的较新浏览器。相反,我建议使用moment.js图书馆。它在浏览器之间保持一致,并且对 ISO 日期和本地化有更好的支持。另外,您还可以获得许多其他有用的解析和格式化功能。
// pass the value from your server
var m = moment('2013-05-02T21:01:26.0828604Z');
// use one of the formats supported by moment.js
// this is locale-specific "long date time" format.
var s = m.format('LLLL');
选项 1 的优点是您可以使用任何时区的时间。如果您可以从下拉列表中询问用户他们的时区,那么您不需要使用任何 Javascript。
选项 2 的优点是您可以让浏览器为您完成一些工作。如果您要发送原始数据(例如对 WebAPI 进行 AJAX 调用),这是最好的方法。然而,JavaScript 只知道 UTC 和浏览器的本地时区。所以如果你需要转换成other zones.
您还应该注意,如果您选择选项 #2,您可能会受到 ECMAScript 5.1 设计缺陷的影响。如果您使用的日期所涵盖的夏令时规则集与当前有效的不同,那么这一点就会发挥作用。您可以阅读更多内容在这个问题中, and 在我的博客上.
如果我们在 HTTP 标头中包含一些时区信息,那就容易多了,但不幸的是我们没有。虽然需要克服很多困难,但这是同时具有灵活性和准确性的最佳方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)