我正在使用.NET MVC 3和SQL Server 2008(r2)开发Web应用程序。
无论如何,我有一个日期时间对象,我想将其转换为用户时间。现在转换为用户时间是相当微不足道的;我有一些java脚本会让我的用户偏离UTC。我知道我的日期时间偏移到UTC。
我昨天意识到,如果他们的生活在一个讨厌的地区,我的用户的抵消将会改变。这将导致旧日期和时间在一段时间内出错。
现在我知道C#有一些实用程序可以转换为时区时间,但它们真的可以处理所有复杂的日光节省吗?
例如。如果我有时间,10-10-2001 8:00:00如何进入太平洋时间?或者,如果我有6-6-2004,我如何进入太平洋时间?
由于滚动日期发生变化,因此非常复杂,我想要一个不需要维护的通用解决方案来设置时区的日期范围。
我知道这是CS中的一个经典问题,但我找不到真正能够100%回答我问题的东西。根据我的看法:C#使用当前年度的日光节省日期来更改每年的日期时间。这可能会导致一些错误。
非常感谢您的帮助。
答案 0 :(得分:2)
现在我知道C#有一些实用程序可以转换成时区时间,但它们真的可以处理所有日光节省的错综复杂吗?
TimeZoneInfo
确实,是 1 。 (它是.NET框架的一部分,不是C#的一部分 - C#只是您碰巧使用的语言。)但是,我认为这不是您真正想要做的。
为什么要将DateTime
存储在服务器的时区?在大多数情况下,将其存储在UTC中更为明智。除此之外,如果您的服务器处于一个观察夏令时的时区,那么当时钟倒流时,您每年会有一小时的模糊不清。 (相同的当地时间出现两次。)
一旦将其存储为UTC,您应该将其作为UTC提供给您的Javascript客户端。虽然你说你有“一些java脚本会让我的用户偏离UTC” - 这将取决于确切的时刻。例如,因为我在英国,我的偏移量有时为0,有时为+1小时。如果将UTC传递回客户端,则可以计算出该UTC时间的本地时间。您的服务器不能,除非您可以从客户端到服务器获得时区的准确表示,这通常是一件棘手的事情。
据我所知:C#使用当前年度的日光节省日期来更改每年的日期时间。
同样,C#本身与此无关。目前尚不清楚.NET框架的哪个部分 - TimeZone
? TimeZoneInfo
? DateTime
? TimeZoneInfo
包含历史数据,但前提是您使用的是支持它的操作系统版本。
1 嗯,就你可能关心而言。它没有TZDB那么多的历史数据,它对俄罗斯和纳米比亚有一些非常奇怪的表现,但它通常有规则变化的想法。
答案 1 :(得分:0)
我发现以下规则是最佳解决方案:
var nowDate =DateTime.UtcNow
)。 服务器日期应与位置无关,这样就不会产生混淆。在客户端使用UTC时也处理原始数据,但在UI中显示转换为浏览器本地时间的日期(这将是操作系统中配置的任何时间) 。 好消息是,这已经是浏览器的内置功能!我们只需要让它们更容易处理它。 这意味着如果我们有一个javascript客户端代码POSTing / PUTing / PATCHing数据到服务器并使用JSON从服务器获取数据, JSON应该使用UTC中的ISO 8601(本机支持)(以Z结尾)< / strong>好像你在做:
var dateNow = new Date(); //Wed May 11 2016 13:06:21 GMT+1200 (New Zealand Standard Time)
var dateNowIso = dateNow.toISOString(); //"2016-05-11T01:06:21.147Z"
然后,只需依靠浏览器功能即可将任何UTC日期自动转换为当前本地时间,反之亦然。只要格式为Date
对象,浏览器的javascript引擎就能在UI中显示正确的本地时间。
关于如何为.NET服务器实现它的说明&amp; Javascript客户端场景:例如,我在客户端javascript代码中使用AngularJS(带有restangular),在服务器端使用MVC 6(ASP.NET Core 1.0)。
来自服务器的JSON可能包含日期属性,但在JSON中,类型是一个字符串,例如:
{
"myDateField":"2016-05-11T05:00:00Z"
}
为了依靠浏览器的能力来正确处理UTC时间并将它们转换为本地浏览器,我需要将这个UTC日期字符串解析为真正的javascript Date对象,所以我使用了正则表达式匹配任何看起来像ISO 8601格式的UTC日期的文本值(在我的例子中,这个代码在一个restangular响应拦截器,但它可以在任何地方):
const regexIso8601 = /((((\d{4})(-((0[1-9])|(1[012])))(-((0[1-9])|([12]\d)|(3[01]))))(T((([01]\d)|(2[0123]))((:([012345]\d))((:([012345]\d))(\.(\d+))?)?)?)(Z|([\+\-](([01]\d)|(2[0123]))(:([012345]\d))?)))?)|(((\d{4})((0[1-9])|(1[012]))((0[1-9])|([12]\d)|(3[01])))(T((([01]\d)|(2[0123]))(([012345]\d)(([012345]\d)(\d+)?)?)?)(Z|([\+\-](([01]\d)|(2[0123]))([012345]\d)?)))?))/;
function convertDateStringsToDates(input: any): void {
// Ignore things that aren't objects.
if (typeof input !== "object") {
return input;
}
for (var key in input) {
if (!input.hasOwnProperty(key)) {
continue;
}
let value = input[key];
let match: RegExpMatchArray;
// Check for string properties which look like dates.
if (angular.isArray(value)) {
angular.forEach(value, (val, key) => {
convertDateStringsToDates(val);
});
} else if (angular.isString(value) && (match = value.match(regexIso8601))) {
let milliseconds = Date.parse(match[0]);
if (!isNaN(milliseconds)) {
input[key] = new Date(milliseconds);
}
} else if (angular.isObject("object")) {
// Recurse into object
convertDateStringsToDates(value);
}
}
}
这样我可以将我的javascript对象与正确的Date对象一起使用。
在服务器端(MVC6或WebAPI2 ..)我有一条指令告诉我的JSON解析器在解析日期时总是使用UTC格式,否则它不会在末尾添加Z字符,这是很重要。 MVC6的示例:
services.AddMvc().AddJsonOptions(opt => {
// json dates always in javascript date format with UTC e.g: "2014-01-01T23:28:56.782Z"
opts.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
});
受this article的启发 更新:有些情况下,如下面的评论所述,在当地时间存储数据可能会很有趣。