2014-05-06 21 views
0

快速环境概述:Azure中WebRole UTC转换为本地时区

我有一个最终被托管作为Azure的Webrole的ASP.NET MVC/AngularJS应用。数据存储在同一个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偏移差异进行了调整(这意味着如果我切换到Mountain Time两者的结果本地结果和Azure结果调整1小时...但仍然是6小时)。我已通过Chrome开发工具确认,在客户端检索到的日期(通过Json)根据网站点击是否为删除(Azure)环境或本地环境而不同(意思是它未被错误修改)上的任何客户端后 - 事实)

这里是最有说服力的事情:

如果我转换日期为字符串返回给客户之前下发的字符串出现在JSON响应正确。如果我将它保留为.NET DateTime类型(作为复杂对象的属性),则Json序列化程序似乎会再次进行翻译,但只有在Azure中托管时才会进行翻译。这表明问题与我返回日期的DateTimeKind有关。尽管在这一点上,我几周以来一直在迷失方向,看看为什么我的本地环境和Azure主机环境在序列化方面的差异,以及为什么一次一件事是正确的,另一次是将其转换两次。如果DateKindTime错误,两个环境都不会执行相同的转换吗?

感谢您阅读本文,我会很感激任何想法解决任何人。

回答

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'); 
+0

小心,这将得到*当前*时区偏移量 - 不一定是适用于有问题的值的偏移量。而且,根本不需要指定区域,因为时刻会自动处理该区域。只需调用构造函数并传递值即可。请参阅[这些文档](http://momentjs.com/docs/#/parsing/asp-net-json-date/)。 –

+0

是的,你是对的没有必要指定区域。我会更新我的回答 – nomail

+0

固定为雅。如果你使用'moment.utc',除非你调用'.local()',否则结果将会是utc。由于这种特定的输入格式隐含地是UTC,因此您可以直接解析它。如果您使用带有“Z”说明符的ISO格式,或者使用了某个特定的偏移量,则相同。只有在输入中没有上下文的情况下,您可能需要明确使用'moment.utc(...)'。但是我们在这里得到了主题! :) –

1

这很难肯定地说没有看到更多的代码,但是会不会是这个问题是在路上转换在,而不是出路何在?你说你正在使用TimeZoneInfo.ConvertTimeFromUtc作为输出。你是否也在另一边使用TimeZoneInfo.ConvertTimeToUtc?如果是这样,那很可能是选择当地时区的来源。

你也可能在某个地方打电话给DateTime.ToUniversalTime,它再次使用当地时区。

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

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

当然,你真的不希望服务器的时区影响结果。

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

相关问题