快速环境概述:
我有一个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错误,两个环境都不会执行相同的转换吗?
感谢阅读本文,我很感激有任何想法可以解决任何问题。
答案 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创建新项目。这将帮助您验证您的假设,并可能会追踪问题的根源。如果它仍然失败,那么你将会更好地寻求帮助。