关于c#:时区战略

Timezone Strategy

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

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

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

对于如何作为一个总体战略来处理这一问题有什么建议吗?

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

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

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

如此喜欢

1
2
[DateRange]
Public DateTime MyDate

我可以吃点像

1
2
[ConvertToUTC(offset)]
Public DateTime MyDate

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

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

编辑2我正在寻找类似于http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueConverter.aspx的MVC 3视图和视图模型。

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

需要注意的是,对于这些方法,您必须使用editfor和displayfor而不是像textforfor这样只作为editfor和displayfor使用的元数据提供程序,这些元数据提供程序用于告诉MVC如何在模型上显示该类型的属性。如果直接在视图(@model.mydate)中访问模型值,则不会进行转换。


您可以使用网站范围内的日期时间显示模板来处理将UTC转换为用户本地时间的问题。

从您的视图中,您将使用@html.displayfor(n=>n.myDateTimeProperty)

第二个问题更难解决。要将用户本地时间转换为UTC,可以重写默认的ModelBinder。特别是方法setproperty。这里是一个简单的实现,它演示了这一点。它只适用于日期时间,但可以很容易地扩展到日期时间?。然后在global.asax中将其设置为默认活页夹。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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用户的时区的副本?我同意大多数投票赞成这一回应:

The most popular (==standard?) way of determining the time zone I've
seen around is simply asking the user herself. If your website
requires subscription, this could be saved in the users' profile data.
For anon users, the dates could be displayed as UTC or GMT or some
such.

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

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

当收集来自用户的输入时,通过日期时间从UTC到UTC的转换就足够了。当客户机是托管代码时,datetimeoffset非常好;但是,使用纯HTML/javascript,它不会给您带来太多好处。此外,大多数应用程序不一定需要datetimeoffset的附加信息,除非您打算向其他用户显示原始时区信息。

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.

您不应该依赖于勤奋来正确的日期+时间格式和解析。NET框架应该为您处理这个问题,对于初学者来说,请参见"如何:为ASP.NET网页全球化设置区域性和UI区域性"。

闭幕词

坦率地说,这都是颈部疼痛。几年前我们放弃了这个实现,开始以UTC格式传输所有日期+时间信息,然后我们使用javascript转换为本地时间和显示格式。这是我唯一的工作模式。


您可以使用类似momentjs的东西来显示日期/时间。帮助设置格式和本地时间。


这是不可能自动进行的,你将不得不做一些手工工作。

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

1.1没有MaSTEPAGE:因为CsApPest.NET建议使用JavaScript的GETDATETMEOFSET()来获得时区偏移量,在Cookie中设置值,如果没有cookie,则编写一个模块来检查Cookie,插入Java脚本代码和Cookie使用模块。

1.2使用masterpage:相同,但无需编写模块进行检查。

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