时区策略 [英] Timezone Strategy

查看:22
本文介绍了时区策略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个 MVC 3 应用程序,其中用户可能不在同一个时区,所以我的意图是以 UTC 存储所有内容,并在视图中从 UTC 转换为本地时间,在提交时将本地时间转换为 UTC.

虽然似乎没有很多好的解决方案,但进行一些浏览.老实说,我有点期望至少有一个属性可用于将 UTC 时间自动转换为本地时间,但它似乎不存在.

我觉得只是努力将每个输入手动转换为 UTC 并将每个视图手动转换为本地时间显示将非常容易出错,并导致难以检测到时间未转换为或从哪里转换的错误.

关于如何将其作为一般策略处理的任何建议?

编辑每个人似乎都非常坚持我如何获得客户端时区"这一块,正如我在其中一个评论中提到的那样,这不是我关心的问题.我对确定他们的时区的用户设置很好,所以假设我已经知道客户端时区是什么......这不能解决我的问题.

现在,在我渲染日期的每个视图上,我都需要调用一个方法以从 UTC 在本地时区渲染它.每次我向服务器发送提交日期时,我都需要将其从本地时区转换为 UTC.如果我忘记执行此操作,将会出现问题...提交的日期会出错,或者客户端报告和过滤器会出错.

我希望存在的是一种更自动化的方法,特别是因为视图模型在 MVC 3 中是强类型的,我希望 sum magic 至少能够在时区自动渲染,如果不处理提交,就像日期格式或范围可以由属性控制一样.

很喜欢

[日期范围]公共日期时间 MyDate

我可以有类似的东西

[ConvertToUTC(offset)]公共日期时间 MyDate

无论如何,我想我唯一的方法是编写自定义数据注释以在时区中呈现它,并覆盖 MVC 3 模型绑定器,以便转换传入日期,除非我想包装任何日期在方法调用中.因此,除非有人有进一步的意见或建议,否则它将是这两个选项之一,我只是很惊讶没有什么东西可以做到这一点.

如果我确实实施了解决方案,我一定会发布它.

编辑 2像这样 http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx 用于 MVC 3 视图和视图模型是我正在寻找的.

最终编辑我将 Epignosisx 的答案标记为正确,但也有一些评论要添加.我在这里发现了类似的东西:http://dalldorf.com/blog/2011/06/mvc3-timezones-1/通过将时区放在第 2 部分中想要的人的 cookie 中,从客户端获取时区的实现(下面的链接,因为文章第一部分到第 2 部分的链接不起作用)http://dalldorf.com/blog/2011/09/mvc3-timezones-2/

重要的是要注意这些方法,您必须使用 Editfor 和 Displayfor 而不是 TextForFor 之类的东西,因为只有 EditFor 和 DisplayFor 使用元数据提供程序来告诉 MVC 如何在模型上显示该类型的属性.如果您直接在视图 (@Model.MyDate) 中访问模型值,则不会发生转换.

解决方案

您可以通过使用网站范围的 DisplayTemplate for DateTime 来处理将 UTC 转换为用户本地时间的问题.

从您的视图中,您将使用 @Html.DisplayFor(n => n.MyDateTimeProperty)

第二个问题更难解决.要将用户本地时间转换为 UTC,您可以覆盖 DefaultModelBinder.特别是 SetProperty 方法.这是一个简单的实现,它证明了这一点.它仅适用于 DateTime,但可以轻松扩展到 DateTime?.然后将其设置为 Global.asax 中的默认活页夹

公共类 MyDefaultModelBinder : DefaultModelBinder{protected override void SetProperty(ControllerContext controllerContext,ModelBindingContext bindingContext,System.ComponentModel.PropertyDescriptor propertyDescriptor,对象值){//日期时间的特殊情况if(propertyDescriptor.PropertyType == typeof(DateTime)){if (propertyDescriptor.IsReadOnly){返回;}尝试{如果(值!= null){DateTime dt = (DateTime) 值;propertyDescriptor.SetValue(bindingContext.Model, dt.ToUniversalTime());}}捕捉(例外前){string modelStateKey = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name);bindingContext.ModelState.AddModelError(modelStateKey, ex);}}别的{//处理所有其他类型base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);}}}

I am building a MVC 3 application where the users may not be in the same time zone, so my intent was to store everything in UTC and convert from UTC to local time in the views and localtime to UTC on submissions.

Doing some browsing though there doesn't seem to be a lot of good solutions to this. To be honest, I sort of expected an attribute to be available to auto convert UTC time into local time at least, but it seems not to exist.

I feel like just trying to be diligent about manually converting every input to UTC and manually converting every view to local time display will be very error prone and lead to difficult to detect bugs where the time is not converted to or from.

Any suggestions on how to deal with this as a general strategy?

EDIT Everyone seems very stuck on the "how do I get the client timezone" piece, which as I mention in one of the comments is not my concern. I am fine with a user setting that determines their timezone, so assume I already know what the client time zone is...that doesn't address my problem.

Right now, on each view when I render a date, I would need to call a method to render it in the local time zone from utc. Every time I send a date for submission to the server I need to convert it from the local timezone to UTC. If I forget to do this there will be problems...either a submitted date will be wrong or client side reports and filters will be wrong.

What I was hoping existed was a more automated method, especially since the view model is strongly typed in MVC 3 I was hoping for sum magic to be able to at least automatically render in a time zone, if not handle the submission, just like the date format or range can be controlled by an attribute.

So like

[DateRange]
Public DateTime MyDate

I could have something like

[ConvertToUTC(offset)]
Public DateTime MyDate

Anyway, I guess it look like my only approach would be to write a custom data annotation to render it in a time zone, and a override on the MVC 3 model binder so incoming dates are converted unless I want to wrap ever date in a method call. So unless anyone has further comments or suggestions it will be one of those two options, I'm just surprised something doesn't exist already to do this.

If I do implement a solution I will be sure to post it.

Edit 2 Something like This http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx for MVC 3 views and view models is what I am looking for.

Final Edit I marked epignosisx answer as correct, but also have a few comments to add. I found something similar here: http://dalldorf.com/blog/2011/06/mvc3-timezones-1/ With an implementation of getting the timezone from the client by placing it in the cookie for people that want that in part 2 (link below since the link on the first part of the article to part 2 doesn't work) http://dalldorf.com/blog/2011/09/mvc3-timezones-2/

Its important to note with these approaches that you MUST you Editfor and Displayfor instead of things like TextForFor as only EditFor and DisplayFor make use of the metadata providers used to tell MVC how to display the property of that type on the model. If you access the model values directly in the view (@Model.MyDate) no conversion will take place.

解决方案

You could handle the problem of converting UTC to user local time by using website-wide DisplayTemplate for DateTime.

From your Views you would use @Html.DisplayFor(n => n.MyDateTimeProperty)

The second problem is tougher to tackle. To convert from user local time to UTC you could override the DefaultModelBinder. Specifically the method SetProperty. Here is a naive implementation that demonstrates the point. It only applies for DateTime but could easily be extended to DateTime?. Then set it up as your Default binder in the Global.asax

public class MyDefaultModelBinder : DefaultModelBinder
{
    protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
    {
        //special case for DateTime
        if(propertyDescriptor.PropertyType == typeof(DateTime))
        {
            if (propertyDescriptor.IsReadOnly)
            {
                return;
            }

            try
            {
                if(value != null)
                {
                    DateTime dt = (DateTime)value;
                    propertyDescriptor.SetValue(bindingContext.Model, dt.ToUniversalTime());
                }
            }
            catch (Exception ex)
            {
                string modelStateKey = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name);
                bindingContext.ModelState.AddModelError(modelStateKey, ex);
            }
        }
        else
        {
            //handles all other types
            base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
        }
    }
}

这篇关于时区策略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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