使用一致的时区解释解析javascript日期?

时间:2015-06-27 12:46:34

标签: javascript date datetime

假设我有两种不同类型的日期字符串 - 一个mysql日期戳和一个mysql日期+时间戳。

"2015-12-25"
"2015-12-25 00:00:00"

当我在JavaScript中解析这些时,我得到:

new Date("2015-12-25");
Thu Dec 24 2015 19:00:00 GMT-0500 (Eastern Standard Time)
new Date("2015-12-25 00:00:00");
Fri Dec 25 2015 00:00:00 GMT-0500 (Eastern Standard Time)

或者,在UTC中:

new Date("2015-12-25").toUTCString();
"Fri, 25 Dec 2015 00:00:00 GMT"
new Date("2015-12-25 00:00:00").toUTCString();
"Fri, 25 Dec 2015 05:00:00 GMT"

以某种方式添加时间会使日期解析成为我的时区小时。我想要的是某种功能,使这些都解析为同一个东西--GMT或不,我可以调整,只要结果已知是一个或另一个,无论传递的日期字符串。

我在实现一个涉及正则表达式和检测日期格式的解决方案之前,我认为可能有更好的方法来解决这个问题。

我找到了一些涉及Date.prototype.getTimezoneOffset()的解决方案,但是对于这两个日期都会返回相同的内容,因为它们被解析为处于同一时区。

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

ECMAScript ed 5.1(又名ES5)要求将ISO 8601日期字符串解析为UTC,但ISO要求将它们解析为本地字符串。现在,当前的ECMAScript标准(版本6)与ISO一致,需要符合ISO标准的字符串,没有时区可以解析为本地。

<更新> ECMAScript 2016(第7版)再次更改,以便将YYYY-MM-DD格式的日期字符串解析为UTC,因此不再符合ISO 8601。< / update>。

因此,无论您是一个行为还是另一个行为取决于浏览器(如果您使用IE 8尝试它,您将获得NaN)。在ES5之前,解析所有字符串是依赖于实现的。

" 2015年12月25日"是一个没有时区的有效ISO 8601字符串,因此应根据ES5规则处理为UTC,并按照第6条规则处理。

" 2015-12-25 00:00:00"不是有效的ISO字符串(缺少" T"日期和时间之间),因此浏览器可以解析它们(非ISO字符串的解析在所有版本的ECMAScript中都依赖于实现)。

底线是不要使用Date构造函数来解析字符串(或 Date.parse )。自己解析它们。

要解析类似ISO的字符串,请使用以下内容。它将没有偏移的字符串视为UTC(每ES5),但现在可能应该更改为本地:

/**
 * Parse an ISO string with or without an offset
 *   e.g. '2014-04-02T20:00:00-0600'
 *        '2014-04-02T20:00:00Z'
 *        '2014-02'
 *
 * Allows decimal seconds if supplied
 *   e.g. '2014-04-02T20:00:00.123-0600'
 *
 * If no offset is supplied (or it's Z), treat as UTC (per ECMA-262)
 *
 * If date only, e.g. '2014-04-02' or '2014-02', treat as UTC date (per ECMA-262)
 * All parts after year are optional
 * Don't allow two digit years to be converted to 20th century years
 * @param {string} s - ISO 860 date string
*/
function parseISOString(s) {
  var invalidDate = new Date(NaN);
  var t = s.split(/\D+/g);
  var hasOffset = /[-+]\d{4}$/.test(s);

  // Whether decimal seconds are present changes the offset field and ms value
  var hasDecimalSeconds = /[T ]\d{2}:\d{2}:\d{2}\.\d+/i.test(s);
  var offset = hasDecimalSeconds? t[7] : t[6];
  var offSign;
  var yr  = +t[0],
      mo  = t[1]? --t[1] : 0,
      da  = +t[2] || 1,
      hr  = +t[3] || 0,
      min = +t[4] || 0,
      sec = +t[5] || 0,
      ms  = hasDecimalSeconds? +t[6] : 0,
      offSign = hasOffset? /-\d{4}$/.test(s)? 1 : -1 : 0,
      offHr   = hasOffset? offset/100 | 0 : 0,
      offMin  = hasOffset? offset%100 : 0;

  // Ensure time values are in range, otherwise invalid date.
  // Values can't be -ve as splitting on non-digit character
  if (hr > 24 || min > 59 || sec > 59 || ms > 1000 || offHr > 24 || offMin > 59){
    return invalidDate;
  }

  // Create a date object from date parts, check for validity
  // Avoid two digit years being converted to 20th century
  var d = new Date();
  d.setUTCFullYear(yr, mo, da);

  // Check that date values are valid
  if (d.getUTCFullYear() != yr || d.getUTCDate() != da) {
    return invalidDate;
  }

  // If there's an offset, apply it to minutes to get a UTC time value
  min = hasOffset? +min + offSign * (offHr * 60 + offMin) : min;

  // Set UTC time values of d
  d.setUTCHours(hr, min, sec, ms);

  return d;
}

它可以减少到不到一半,但它的编写易于阅读和维护。

相关问题