在Azure WebRole中将UTC转换为本地时区

时间:2014-05-06 21:27:37

标签: asp.net-mvc json date datetime azure

快速环境概述:

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

问题:

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

return TimeZoneInfo.ConvertTimeFromUtc(UtcDate, _lookup[TimeZoneID]);

整个应用程序中没有任何地方存在DateTime.Now或我希望使用服务器时间设置的任何其他日期转换。

在应用程序的特定区域中,日期以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 Dev Tools确认,在客户端(通过Json)检索的相关日期根据网站点击是删除(Azure)环境还是本地环境(意味着未正确修改)而有所不同在事后的任何地方)

这是最有说服力的事情:

如果我在将日期返回给客户端之前将日期转换为字符串,则发送的字符串在Json响应中显示正确。如果我将其保留为.NET DateTime类型(作为复杂对象的属性),Json序列化程序似乎会再次翻译它,但仅限于在Azure中托管时。这告诉我这个问题与我返回的日期的DateTimeKind有某种关系。虽然,在这一点上,我在几周内迷失了,看看为什么我的本地环境和Azure主机环境之间的序列化差异,以及为什么一件事情是正确的,另一件事情将其转换两次。如果DateKindTime错误,两个环境都不会执行相同的转换吗?

感谢阅读本文,我很感激有任何想法可以解决任何问题。

2 个答案:

答案 0 :(得分:1)

这是一篇很长的帖子:) 如果我是你,我将以UTC格式传输所有dateTimes。就我而言,服务器基本上必须使用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 正如马特约翰逊指出的那样,你可以在当前时区缩短它。

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

答案 1 :(得分:1)

在没有看到更多代码的情况下确定很难说,但问题是在 中的转换方式而不是在出路上进行转换?您说您使用TimeZoneInfo.ConvertTimeFromUtc作为输出。你还在另一边使用TimeZoneInfo.ConvertTimeToUtc吗?如果是这样,那可能是您获取当地时区的来源。

您可能也会在某处调用DateTime.ToUniversalTime,再次使用本地时区。

另一个可能是罪魁祸首的领域 - 当您从Mongo检索您的值时,请检查返回值的Kind。如果他们是Unspecified,那么当他们被序列化为JSON时,他们将被视为Local。基本上,有一个ToUniversalTime电话正在进行中。因此,您可能需要明确调用DateTime.SpecifyKind将值设置为Utc才能出门。

关于Azure的具体问题,它遵循将服务器时区设置为UTC的最佳做法。您可以在自己的机器上尝试,看看是否得到类似的结果。

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

您可能需要考虑使用minimal, complete, and verifiable example创建新项目。这将帮助您验证您的假设,并可能会追踪问题的根源。如果它仍然失败,那么你将会更好地寻求帮助。