使用getTimezoneOffset将UTC日期时间转换为本地日期时间时,在IE和Chrome中获得不同的结果

时间:2017-01-25 19:13:19

标签: javascript jquery date datetime

我正在使用以下逻辑将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上的多个相关帖子,但是每个帖子都有多条评论指出了每种方法的缺点。

假设客户端计算机上的本地时区是正确的,最好的方法是什么。

1 个答案:

答案 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());