2013-05-02 88 views
12

我将所有DateTime字段存储为UTC时间。当用户请求网页时,我想采用他首选的本地时区(而不是服务器本地时区),并自动将所有Web表单中的所有DateTime字段显示为本地日期。将UTC日期时间全局转换为用户指定的本地日期时间

当然,我可以在每个窗体的每个DateTime.ToString()调用上应用转换,或者实现一些辅助工具,但这是一个耗时的任务,还有一些第三方组件很难配置自定义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,如果它很重要。

回答

3

简短的答案是,你不能。 HTTP不需要(甚至不提供标准方式)用户代理(浏览器)在HTTP请求中提供本地时间或时区信息。

您可能需要

  • 要求用户提供其首选的时区,或
  • 有客户端的JavaScript报告给你以某种方式(饼干吗?AJAX?其他?)

请记住,客户端JavaScript解决方案也不完美。 Javascript禁用(或者对于某些浏览器不存在)。 Javascript可能无法访问时区信息。等

26

你不能直接做你所要求的,但我会建议一些替代品。正如尼古拉斯指出的那样,HTTP中没有任何东西可以直接给你时区。

选项1

  • 首先,决定你要使用哪种类型的时区的数据。有两种不同的类型可用,您可以通过TimeZoneInfo课程访问的Microsoft时区,或者世界其他地区使用的IANA/Olson时区。 Read here for more info。我的建议是后者,使用NodaTime提供的实施。

  • 然后确定要将哪个时区转换为。你应该允许你的用户在某个地方选择他们的时区。

    • 你可能会显示一个下拉列表中进行选择的几个时区,或者你可能会做更有用的东西,像显示世界地图的,他们可以单击以选中他们的时区。有几个库可以在Javascript中做到这一点,但我最喜欢的是this one

    • 您可能想要猜测使用的默认时区,因此您可以在从列表(或地图)中选择之前尽可能接近准确。这个名为jsTimeZoneDetect的图书馆很棒。它会询问浏览器的时钟,并且猜测它可能是什么时区。这是相当不错的,但它仍然只是一个猜测。不要盲目使用它 - 但要用它来确定一个起点。 更新您现在还可以使用moment.tz.guess()在moment.js的moment-timezone组件中执行此操作。

  • 现在你知道用户的时区,您可以使用该值将UTC DateTime值转换为本地时区。不幸的是,没有什么可以在线程上设置的。当您更改系统时区时,它对所有进程和线程都是全局的。所以你别无选择,只能将时区传递给你发送回去的每一个地方。 (我相信这是你的主要问题。)See this almost duplicate here.

  • 之前将其转换为字符串,则需要也知道用户所在的区域(这可以从Request.UserLanguages值获得)。您可以将其分配给当前线程,也可以将其作为参数传递给DateTime.ToString()方法。这不会做任何时区转换 - 它只是确保数字处于正确的位置,使用正确的分隔符以及适用于平日或月份名称的语言。

选项2

不要其转换为本地时间在服务器上的。

  • 既然你说你与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的优点是您可以让浏览器为您完成一些工作。如果您发送的是原始数据,例如将AJAX调用到WebAPI,这是最好的方法。但是,JavaScript只知道UTC和浏览器的本地时区。因此,如果您需要将其转换为其他区域,则效果不佳。

您还应该注意,如果您选择选项#2,则可能会受到ECMAScript 5.1设计中的缺陷的影响。如果您使用的夏时制规则所涵盖的日期与当前生效的日期一致,则这会起作用。您可以阅读更多in this questionon my blog

如果我们在HTTP标头中有一些时区信息,那很容易,但不幸的是我们没有。这些是可以跳过的很多环节,但这是兼顾灵活性和准确性的最佳方式。

+0

很好的答案!你说这也可以用JavaScript中的内置Date对象完成。你能否更新你的答案以表明如何做到这一点? – Scott 2013-12-31 17:05:17

+0

@Scott - 已更新。谢谢。 – 2013-12-31 18:04:20

相关问题