时区战略

Ama*_*iel 22 javascript c# timezone utc asp.net-mvc-3

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

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

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

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

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

现在,在我渲染日期的每个视图上,我需要调用一个方法来从utc在本地时区渲染它.每次我向服务器发送提交日期时,我都需要将其从本地时区转换为UTC.如果我忘记这样做会有问题...提交的日期将是错误的或客户端报告和过滤器将是错误的.

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

所以喜欢

[DateRange]
Public DateTime MyDate
Run Code Online (Sandbox Code Playgroud)

我可以有类似的东西

[ConvertToUTC(offset)]
Public DateTime MyDate
Run Code Online (Sandbox Code Playgroud)

无论如何,我想我的唯一方法就是编写自定义数据注释以在时区中呈现它,并在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/ 通过将时区放在cookie中为第2部分中需要的人提供时区的实现(链接如下,因为文章第一部分到第2部分的链接不起作用) http://dalldorf.com/blog/2011/09/mvc3-timezones-2/

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

epi*_*isx 4

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

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

第二个问题更难解决。要将用户本地时间转换为 UTC,您可以覆盖DefaultModelBinder。具体来说是方法SetProperty。这是一个简单的实现来证明这一点。它仅适用于DateTime但可以轻松扩展到DateTime?。然后将其设置为 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)