我正在使用以下逻辑将UTC日期时间(来自此格式2017-01-25T23:08:08.453
的服务器)转换为使用JavaScript的浏览器上的本地日期时间(不要求用户输入他的时区详细信息和假设系统日期时间/客户端机器上的时区是正确的。)
var jsDate = new Date(do.createdAt);
var jsDate = new Date(jsDate.getTime() - jsDate.getTimezoneOffset() * 60000);
登录似乎在IE中工作正常,但在Chrome中我得到的结果不同。
在IE和Chrome中Execute this fiddle看不同的结果。
如果我使用moment.js,我在IE和Chrome中都得到了正确的结果:
moment.utc(do.createdAt).toDate();
但我不想引入额外的依赖。
我查看了SO上的多个相关帖子,但是每个帖子都有多条评论指出了每种方法的缺点。
假设客户端计算机上的本地时区是正确的,最好的方法是什么。
答案 0 :(得分:0)
假设“UTC日期时间”是ISO 8601格式字符串,并且您需要弄乱偏移量,那么它可能在字符串中没有偏移量。此外,如果您在不同的浏览器中获得不同的结果,那么可能不是严格的ISO 8601,例如类似的东西:
"2017-01-25 12:00:00"
缺少“T”分隔符和时区。你可以解析字符串并添加缺少的T和时区(Z会这样做)然后将它留给内置的解析器,你可以跳过一步并直接将它解析为一个日期,或者将它交给一个解析库(有很多可供选择)。
要按照上面的UTC解析ISO 8601之类的字符串,以下内容将完成以下工作:
/* Parse a string without timezone like "2017-01-25 12:00:00" as UTC
** @param {string} s - string to parse
** @returns {Date} returns an invalid date if any
** part is out of range.
*/
function parseAsUTC(s) {
var b = s.split(/\D/);
var d = new Date(Date.UTC(b[0], --b[1], b[2], b[3], b[4], b[5], b[6]||0));
return d && // generated an object
d.getUTCMonth() == b[1] && // month didn't roll over
d.getUTCHours() == b[3] && // hour didn't roll over
d.getUTCSeconds() == b[5] ? // seconds didn't roll over
d : new Date(NaN);
}
console.log(parseAsUTC('2017-01-25 12:00:00')); // Valid date
console.log(parseAsUTC('2017-01-32 12:00:00')); // Invalid date
console.log(parseAsUTC('2017-01-25T23:08:08.453')); // 2017-01-25T23:08:08.453Z
只需检查一些日期部分,就好像它没有改变一样,然后它和它的下一个最低单位必须在范围内,如果任何一个超出范围,则更高的单位会因滚动而改变超过自己或下一个最高单位。
如果ISO 8601日期字符串缺少时区,例如“2017-01-25T23:08:08.453”,那么如果使用内置解析器进行解析,则 应被视为本地。但是,使用Date构造函数(或Date.parse,它们等效于解析)解析字符串是出了名的不可靠。
因此,对上述建议没有任何更改,而 parseAsUTC 函数也是如此。 : - )
BTW,在你的代码中:
var jsDate = new Date('2017-01-25T23:08:08.453');
var jsDate = new Date(jsDate.getTime() - jsDate.getTimezoneOffset() * 60000);
您可以使用 setMinutes 直接应用时区偏移量,以避免创建不必要的附加日期。但同样,它依赖于内置的解析器,因此坚持使用提供的函数或库:
var s = '2017-01-25T23:08:08.453';
var d = new Date(s);
d.setMinutes(d.getMinutes() - d.getTimezoneOffset());
console.log('Date string : ' + s +
'\nAdjusted date: ' + d.toISOString());