将 UTC 日期时间全局转换为用户指定的本地日期时间 [英] Globally convert UTC DateTimes to user specified local DateTimes

查看:47
本文介绍了将 UTC 日期时间全局转换为用户指定的本地日期时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am storing all the DateTime fields as UTC time. When a user requests a web page, I would like to take his preferred local timezone (and not the local timezone of the server machine) and automatically display all the DateTime fields in all the web forms as local dates.

当然,我可以在每种形式的每个 DateTime.ToString() 调用上应用转换,或者实现一些帮助实用程序,但这是一项耗时的任务,而且还有一些 3rd 方组件很难自定义配置日期时间显示模板.

Of course, I could apply the conversion on every DateTime.ToString() call in every form or implement some helper utility but it is a time consuming task, and also there are some 3rd party components which are tricky to configure with custom DateTime display templates.

本质上,我想让 DateTime 类的行为如下:

Essentially, I would like to make the DateTime class to behave as follows:

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.

BTW, I am using ASP.NET MVC 4, if it matters.

推荐答案

你不能直接按照你的要求去做,但我会建议一些替代方案.正如 Nicholas 所指出的,HTTP 中没有任何内容可以直接为您提供时区.

You can't do directly what you asked for, but I will suggest some alternatives. As Nicholas pointed out, there is nothing in HTTP that would give you the time zone directly.

选项 1

  • 首先,确定您要使用哪种类型的时区数据.有两种不同的类型可用,要么是您可以使用 TimeZoneInfo 类访问的 Microsoft 时区,要么是世界其他地方使用的 IANA/Olson 时区.阅读此处了解更多信息.我的建议是后者,使用 NodaTime 提供的实现.

  • First, decide which type of time zone data you want to work with. There are two different types available, either the Microsoft time zones that you can access with the TimeZoneInfo class, or the IANA/Olson time zones that the rest of the world uses. Read here for more info. My recommendation would be the latter, using the implementation provided by NodaTime.

然后确定要转换到的时区.您应该允许您的用户在某处进行设置以选择他们的时区.

Then determine which time zone you want to convert to. You should allow your user a setting somewhere to pick their time zone.

  • 您可能会显示一个下拉列表以选择多个时区之一,或者您可能会做一些更有用的事情,例如显示世界地图,他们可以单击以选择他们的时区.有几个库可以在 Javascript 中执行此操作,但我最喜欢的是这个.

您可能想猜测要使用的默认时区,以便在他们从列表(或地图)中进行选择之前尽可能接近准确.有一个很棒的库,称为 jsTimeZoneDetect.它将询问浏览器的时钟并对其可能是哪个时区做出最佳猜测假设.这是相当不错的,但它仍然只是一个猜测.不要盲目使用它 - 但一定要用它来确定一个起点.更新您现在也可以使用 moment.tz.guess()moment-timezonemoment.js 组件.

You might want to guess a default time zone to use, so you can be as close to accurate as possible before they pick from the list (or map). There is a great library for this called jsTimeZoneDetect. It will interrogate the browser's clock and make a best guess assumption of what time zone it might be. It is fairly good, but it is still just a guess. Don't use it blindly - but do use it to determine a starting point. Update You can now also do this with moment.tz.guess(), in the moment-timezone component of moment.js.

既然您知道用户所在的时区,您就可以使用该值将您的 UTC DateTime 值转换为该本地时区.不幸的是,您无法在线程上设置任何东西来做到这一点.当您更改系统时区时,它对所有进程和线程都是全局的.因此,您别无选择,只能将时区传递给您将其发回的每个地方.(我相信这是您的主要问题.)在此处查看几乎重复.

Now that you know the time zone of the user, you can use that value to convert your UTC DateTime values to that local time zone. Unfortunately, there is nothing you can set on the thread that will do that. When you change the system time zone, it is global for all processes and threads. So you have no choice but to pass the time zone to each and every place you are sending it back. (I believe this was your main question.) See this almost duplicate here.

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

Before you convert it to a string, you will need to also know the user's locale (which you can get from the Request.UserLanguages value). You can assign it to the current thread, or you can pass it as a parameter to the DateTime.ToString() method. This doesn't do any time zone conversion - it just makes sure that the numbers are in the correct position, using the correct separators, and the appropriate language for names of weekdays or months.

选项 2

不要将其转换为服务器上的本地时间.

Don't convert it to local time on the server at all.

  • 既然您说您使用的是 UTC 值,请确保它们的 .Kind 属性是 Utc.您可能应该在从数据库加载时执行此操作,但如果必须,您可以手动执行此操作:

  • Since you said you are working with UTC values, make sure their .Kind property is Utc. You should probably do this when you load from your database, but if you have to you can do it manually:

myDateTime = DateTime.SpecifyKind(myDateTime, DateTimeKind.Utc);

  • 将其作为纯 UTC 格式以 ISO8601 等不变格式发送回浏览器.换句话说:

  • Send it back to the browser as pure UTC, in an invariant format like ISO8601. In other words:

    myDateTime.ToString("o");  // example:  "2013-05-02T21:01:26.0828604Z"
    

  • 在浏览器上使用一些 JavaScript 将其解析为 UTC.它将自动选择浏览器的本地时间设置.一种方法是在 JavaScript 中使用内置的 Date 对象,如下所示:

    var dt = new Date('2013-05-02T21:01:26.0828604Z');
    

    但是,这仅适用于支持 ISO-8601 格式的较新浏览器.相反,我建议使用 moment.js 库.它在浏览器之间保持一致,并且更好地支持 ISO 日期和本地化.此外,您还可以获得许多其他有用的解析和格式化功能.

    However, this will only work in newer browsers that support the ISO-8601 format. Instead, I recommend using the moment.js library. It is consistent across browsers, and it has better support for ISO dates, and localization. Plus you get a lot of other useful parsing and formatting functions.

    // 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.

    The advantage of Option 1 is that you can work with times in any time zone. If you can ask the user for their timezone from a dropdown list, then you need not use any Javascript.

    选项 2 的优点是您可以让浏览器为您完成一些工作.如果您要发送原始数据,例如对 WebAPI 进行 AJAX 调用,这是最好的方法.但是,JavaScript 只知道 UTC 和浏览器的本地时区.因此,如果您需要转换为其他区域,则效果不佳.

    The advantage of Option 2 is that you get the browser to do some of the work for you. This is the best way to go if you're sending out raw data, such as making AJAX calls to a WebAPI. However, JavaScript is only aware of UTC and the browser's local time zone. So it doesn't work so well if you need to convert to other zones.

    您还应该注意,如果您选择选项 #2,您可能会受到 ECMAScript 5.1 设计缺陷的影响.如果您正在处理的日期与当前有效的夏令时规则集不同,那么这将起作用.您可以阅读更多在这个问题在我的博客上.

    You should also be aware that if you choose Option #2, you may be affected by a flaw in the design of ECMAScript 5.1. This comes into play if you are working with dates that are covered by a different set of daylight saving time rules than are currently in effect. You can read more in this question, and on my blog.

    如果我们在 HTTP 标头中有一些时区信息会容易得多,但不幸的是我们没有.有很多障碍需要跳过,但这是兼顾灵活性和准确性的最佳方式.

    It would be so much easier if we had some time zone information in the HTTP headers, but unfortunately we don't. These are a lot of hoops to jump through, but it's the best way to have both flexibility and accuracy.

    这篇关于将 UTC 日期时间全局转换为用户指定的本地日期时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆