javascript - Date.parse 意外返回字符串

标签 javascript date

我知道关于这个主题有很多答案(太多了,无法全部阅读),但我无法理解为什么 Date.parse 返回

'Sun Oct 21 2018 00:00:00 GMT+0100 (GMT Summer Time)'

来自字符串'2018-10-20T23:00:00Z'

所有返回时间+1小时

我错过了显而易见的事情吗?据推测,这与 +0100 GMT 有关,但我需要做什么才能确保它正确解析?

谢谢

最佳答案

首先,我强烈建议您永远不要使用Date构造函数(或Date.parse,它们对于解析来说是等效的)解析字符串。始终使用小函数或合适的库(下面有链接的建议)。

如果按照 ECMA-262 进行解析,则“2018-10-20T23:00:00Z”将被解析为 UTC。如果您使用 toString (或通过调用 toString 的方法,如 console.log(new Date()))将结果日期发送到输出,那么通常使用主机时区来计算“本地”值。

toString 生成的字符串的格式取决于实现,因此可能不包含时区,或者可能以意外的方式显示它,并且在不同的主机中可能有所不同。

根据 ECMA-262,如果您希望 '2018-10-20T23:00:00Z' 被视为本地,请删除“Z”:

var s = '2018-10-20T23:00:00Z';
var t = s.replace(/z$/i,'');
console.log(t);
console.log(new Date(t).toString());

但是,从我的第一条评论开始,即使省略了 Z,Safari 10.0.3 似乎也会将该字符串视为 UTC,因此您的结果可能不正确,具体取决于主机。 Firefox 似乎做对了。

我必须强调,您不应该依赖 DateDate.parse 进行解析。曾经。

虽然为特定格式编写自己的解析器很容易,但有些人感觉使用库要好得多。考虑fecha.js (它很小并且进行解析和格式化)或 moment.js (这并不完全是娇小的,但也有助于算术,并且可以包括时区功能)。

例如这是一个小型 ISO 扩展格式解析器,它尝试尽可能兼容并尽可能少地使用 Date 方法:

/* Parse ISO date string in format yyyy-mm-ddThh:mm:ss.sss+hh:mm or Z
** @param (string} s - string to parse in ISO 8601 extended format
**                     yyyy-mm-ddThh:mm:ss.sss+/-hh:mm or z
**                     time zone can omit separator, so +05:30 or +0530
** @returns {Date}   - returns a Date object. If any value out of range,
**                     returns an invalid date.
*/
function parseISO(s) {
  // Create base Date object
  var date = new Date();
  var invalidDate = new Date(NaN);
  // Set some defaults
  var sign = -1, tzMins = 0;
  var tzHr, tzMin;
  // Trim leading and trailing whitespace
  s = s.replace(/^\s*|\s*$/g,'').toUpperCase();
  // Get parts of string and split into numbers
  var d  = (s.match(/^\d+(-\d+){0,2}/)             || [''])[0].split(/\D/);
  var t  = (s.match(/[\sT]\d+(:\d+){0,2}(\.\d+)?/) || [''])[0].split(/\D/);
  var tz = (s.match(/Z|[+\-]\d\d:?\d\d$/)          || [''])[0];

  // Resolve timezone to minutes, may be Z, +hh:mm or +hhmm
  // substr is old school but more compatible than slice
  // Don't need to split into parts but makes validation easier
  if (tz) {
    sign  = /^-/.test(tz)? 1 : -1;
    tzHr  = tz == 'Z'? 0 : tz.substr(1,2);
    tzMin = tz == 'Z'? 0 : tz.substr(tz.length - 2, 2)*1;
    tzMins = sign * (tzHr*60 + tzMin);
  }

  // Validation
  function isLeap(year){return year % 4 != 0 || year % 100 == 0 && year % 400 != 0}
  // Check number of date parts and month is valid
  if (d.length > 3 || d[1] < 1 || d[1] > 12) return invalidDate;
  // Test day is valid
  var monthDays = [,31,28,31,30,31,30,31,31,30,31,30,31];
  var monthMax = isLeap(d[0]) && d[1] == 2? 29 : monthDays[d[1]];
  if (d[2] < 1 || d[1] > monthMax) return invalidDate;
  // Test time parts
  if (t.length > 5 || t[1] > 23 || t[2] > 59 || t[3] > 59 || t[4] > 999) return invalidDate;
  // Test tz within bounds
  if (tzHr > 12 || tzMin > 59) return invalidDate;

  // If there's a timezone, use UTC methods, otherwise local
  var method = tz? 'UTC' : '';
  
  // Set date values
  date['set' + method + 'FullYear'](d[0], (d[1]? d[1]-1 : 0), d[2]||1);
  // Set time values - first member is '' from separator \s or T
  date['set' + method + 'Hours'](t[1] || 0, (+t[2]||0) + tzMins, t[3]||0, t[4]||0);

  return date;
}

console.log('UTC  : ' + parseISO('2018-10-20T23:00:00Z').toString());
console.log('Local: ' + parseISO('2018-10-20T23:00:00').toString());

关于javascript - Date.parse 意外返回字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42148067/

相关文章:

Javascript : why copy value but not change

python - 读取.dat文件日期字符串

model-view-controller - 比较日期 DataAnnotations Validation asp.net mvc

php - 比较来自 MySql 和 Datepicker 的日期

javascript - 拖放 div

javascript - 从 React Admin 中的同一端点创建多个资源以应用不同的过滤器

c# - 使用日期(2015 年 9 月 11 日 --> 日期格式)按降序对 C# 列表进行排序?

java - JPA:如何以日期为键映射 map

javascript - 默认使用 xsl :when test? 返回所有元素

javascript - React Redux Form 文本区域上的字符计数器