Asp.net mvc 在Azure WebRole中将UTC转换为本地时区

Asp.net mvc 在Azure WebRole中将UTC转换为本地时区,asp.net-mvc,json,date,datetime,azure,Asp.net Mvc,Json,Date,Datetime,Azure,快速环境概述: 我有一个ASP.NET MVC/AngularJS应用程序,它最终将作为Azure Webrole托管。数据存储在同一Azure数据中心托管的MongoDB中(通过MongoLab)。开发环境和登台环境(Azure)指向同一个MongoDB数据库,因此可以看到完全相同的数据 问题: 应用程序的各个用户将其首选时区存储为字符串(TimezoneID)。应用程序中的所有日期都存储为UTC时间。通过扩展方法在服务器上完成UTC时间与用户特定时区之间的转换,该扩展方法最终调用: retu

快速环境概述:

我有一个ASP.NET MVC/AngularJS应用程序,它最终将作为Azure Webrole托管。数据存储在同一Azure数据中心托管的MongoDB中(通过MongoLab)。开发环境和登台环境(Azure)指向同一个MongoDB数据库,因此可以看到完全相同的数据

问题:

应用程序的各个用户将其首选时区存储为字符串(TimezoneID)。应用程序中的所有日期都存储为UTC时间。通过扩展方法在服务器上完成UTC时间与用户特定时区之间的转换,该扩展方法最终调用:

return TimeZoneInfo.ConvertTimeFromUtc(UtcDate, _lookup[TimeZoneID]);
在整个应用程序中没有DateTime。现在或任何其他日期转换,我希望使用服务器时间设置

在应用程序的特定区域中,日期存储在Mongo(UTC)中。我可以确认日期是否正确存储为UTC(基于与本地时间的偏移量)。当我从数据存储中检索该日期并将其转换回我的本地时间(中央标准时间)时,我跳过上面的代码行,转换工作正常,并且设置了本地时间。结果作为API调用的Json结果的一部分发送到客户端浏览器,并正确显示给用户。在传输过程中,MVC Json序列化程序将日期时间解析为类似以下格式:

EventDate: "/Date(1399407153971)/"
我用Javascript解析并相应地显示,一切都很好

当我将完全相同的代码部署到Azure(它指向Mongo中完全相同的数据存储)时,通过API调用得出的结果似乎已经应用了UTC转换两次(这意味着常规的6小时UTC偏移量应用了两次,显示的日期比UTC早12小时…比我想要的早6小时)

我已经将Mongo中存储的时间更新了一两分钟,以确保双方都进行了更新(验证相同的数据)。我已经修改了本地计算机的日期/时间设置,以查看它是否对本地结果有任何影响,但没有影响。我已经在应用程序中更改了所选用户的时区,并且我的本地结果和Azure返回的结果都会根据中心标准时间和新时区之间的UTC偏移量差异进行调整(这意味着如果我切换到山区时间,则本地结果和Azure结果的结果都会调整1小时…但仍然会间隔6小时)。我已经通过Chrome开发工具确认,在客户端(通过Json)检索到的有问题的日期是不同的,这取决于所访问的站点是删除(Azure)环境还是本地环境(这意味着在事件发生后客户端上的任何位置都没有被错误修改)

以下是最能说明问题的一点:

如果在将日期返回给客户机之前将其转换为字符串,则发送的字符串在Json响应中看起来是正确的。如果我将其保留为.NET DateTime类型(作为复杂对象的属性),Json序列化程序似乎会再次对其进行转换,但仅当托管在Azure中时。这让我想到了与日期时间相关的问题我返回的日期类型。虽然,在这一点上,我在这几周里太迷茫了,不明白为什么我的本地环境和Azure主机环境在序列化方面存在差异,为什么一次一件事情是正确的,而另一件事情将它转换两次。如果DateKindTime是错误的,那么两个环境不会执行相同的转换吗

感谢您通读本文,我将非常感谢您提出的任何想法。

这是一篇很长的帖子:) 如果我是你,我会以UTC格式传输所有日期时间。就我而言,服务器基本上必须使用UTC时间。必须在客户端应用对客户端时间的转换。您可以使用momentjs库,它被证明是处理日期和时间的非常好的库

在客户端执行类似的操作

var date = {
      utc: '/Date(1399407153971)/', //time that you have recieved 
      offset: 240
            }

var localTime = moment.utc(date.utc).zone(date.offset).format('DD/MM/YYYY hh:mm');
我希望这有帮助

UPD 正如马特·约翰逊(Matt Johnson)所指出的,对于当前时区,您可以将其缩短

var localTime = moment('/Date(1399407153971)/').format('DD/MM/YYYY hh:mm');

在没有看到更多代码的情况下很难确定,但问题是否在于输入过程中的转换,而不是输出过程中的转换?您说过您正在使用
TimeZoneInfo.ConvertTimeFromUtc
作为输出。您是否还在另一端使用
TimeZoneInfo.ConvertTimeToUtc
?如果是这样的话,那很可能就是获取本地时区的来源

var localTime = moment('/Date(1399407153971)/').format('DD/MM/YYYY hh:mm');
您可能还在某个地方调用了
DateTime.ToUniversalTime
,它同样使用本地时区

var localTime = moment('/Date(1399407153971)/').format('DD/MM/YYYY hh:mm');
另一个可能是罪魁祸首的方面——当您从Mongo检索值时,请检查返回值的
种类。如果它们是
未指定的
,那么当它们被序列化为JSON时,它们将被视为是
本地的
。基本上,有一个
ToUniversalTime
呼叫正在引擎盖下进行。因此,您可能需要显式调用
DateTime.SpecifyKind
将值设置为
Utc
,然后它才能出门

对于Azure,它遵循将服务器时区设置为UTC的最佳实践。你可以在自己的机器上试试,看看是否能得到类似的结果

当然,您根本不希望服务器的时区影响结果


<>您可能想考虑用A创建一个新项目。这将帮助您验证您的假设,并可能追踪问题的根源。如果仍然失败,那么您就可以更好地寻求帮助。

小心,这将获得当前时区偏移量,而不一定是应用于所讨论的值的偏移量。此外,根本不需要指定区域,因为矩会自动处理该问题。只需调用矩构造函数并传递值。看。是的,你是对的,不需要指定区域。我会更新我的答案,帮你解决这个问题。如果您使用
momen