时区策略

Timezone Strategy

本文关键字:策略 时区      更新时间:2023-09-26

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

进行一些浏览,尽管似乎没有太多好的解决方案。老实说,我有点希望至少有一个属性可以将UTC时间自动转换为本地时间,但它似乎并不存在。

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

关于如何将其作为一项总体战略来处理,有什么建议吗?

编辑 每个人似乎都非常纠结于"我如何获得客户时区"这一条,正如我在其中一条评论中提到的,这不是我关心的问题。我对确定他们时区的用户设置很满意,所以假设我已经知道客户端时区是什么……这并不能解决我的问题。

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

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

就像

[DateRange]
Public DateTime MyDate

我可以买一些类似的东西

[ConvertToUTC(offset)]
Public DateTime MyDate

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

如果我真的实现了一个解决方案,我一定会发布它。

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

最终编辑我将epinosisx的答案标记为正确,但也有一些评论需要添加。我在这里发现了类似的东西: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 中的默认活页夹

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);
        }
    }
}

首先,这主要是"如何确定web用户的时区?"的重复?,我同意大多数人对这一回应的投票:

我最常用的(==标准?)确定时区的方法周围看到的只是询问用户自己。如果您的网站需要订阅,这可以保存在用户的配置文件数据中。对于匿名用户,日期可以显示为UTC或GMT或某些这样的

也就是说,自动设置该值的最常见方法是使用javascript的DategetTimezoneOffset()。然后可以通过cookie或ajax请求将其反馈到服务器,并与用户的配置文件、会话或cookie一起存储。

最终,我仍然认为您应该允许用户更改此设置,这样您不仅可以确定UTC偏移,还可以确定实际时区和夏令时信息。

当从用户收集输入时,通过DateTime转换到UTC和从UTC转换应该足够了。当客户端是托管代码时,DateTimeOffset非常好;然而,使用纯html/javascript并不会给您带来太多好处。此外,大多数应用程序不一定需要DateTimeOffset的附加信息,除非您打算向其他用户显示原始时区信息。

我只是想努力手动转换输入到UTC并手动将每个视图转换为本地时间显示将非常容易出错,并导致难以检测到错误时间不转换为或从中转换。

您不应该依赖勤奋来获得正确的日期+时间格式和解析。.NET框架应该为您处理此问题,请参阅"如何:设置ASP.NET网页全球化的区域性和UI区域性"。

结束语

坦率地说,这真是令人头疼。几年前,我们放弃了该实现,并开始以UTC传输所有日期+时间信息,然后我们使用Javascript转换为本地时间和显示格式。这实际上是唯一工作模型IMHO。

您可以使用MomentJS之类的东西来显示日期/时间。有助于格式化和本地时间。

这不是自动实现的,您将不得不做一些手动工作。

1如果您不想将用户的时区存储在数据库中

1.1没有主页:正如csharptest.net建议的那样,使用java脚本的getDateTimeOffset()来获取时区偏移量,在cookie中设置值,如果cookie不存在,则编写一个模块来检查cookie。插入java脚本代码和cookie使用模块。

1.2使用母版页:同样的事情,但不需要编写用于检查的模块。

2将用户的时区存储在数据库中(最佳和最简单)无需使用javascript获取时区,只需根据用户的时区转换日期时间即可。