为什么Date(" 2014-04-07")解析为2014年4月5日星期六17:26:15 GMT-0500(CEST)?

时间:2014-04-05 15:23:28

标签: javascript date

我正在创建这样的日期:

var StartDate = new Date(data.feed.entry[i].gd$when[j].startTime);

收到日期字符串时,在表格中指定日期和时间:

"2014-04-12T20:00:00.000-05:00"

Date()解释这个完美的回归:

Sat Apr 12 2014 19:00:00 GMT-0500 (CDT)

但是,当收到日期字符串时,表格中没有时间信息:

"2014-04-07" 

然后Date()将其解释为:

Sat Apr 05 2014 19:00:00 GMT-0500 (CDT)

看起来Date()正在把-07作为时间,我不知道它在哪里得到的日期是05.任何想法可能是什么问题? 可能是,不知何故,Date()正在解释不同的时区,因为在第一个字符串中,时区是在最后确定的,但在“全天”事件中没有时区的指示。

有人发现了这个问题吗?如果是的话,你是怎么解决的?

更新:在研究了一点这个解析问题后,我发现了一些非常奇怪的东西:

以下声明:

 new Date("2014-4-07")

将返回2014年4月7日星期一00:00:00 GMT-0500(CDT),这是正确的,但是以下一个:

  new Date("2014-04-07")

返回2014年4月6日星期日19:00:00 GMT-0500(CDT),这是错误的。所以,无论出于何种原因,似乎填充零都会影响解析日期的方式!

3 个答案:

答案 0 :(得分:1)

您使用Date()功能错误。

它只接受以下格式的参数。

//No parameters
var today = new Date();

//Date and time, no time-zone
var birthday = new Date("December 17, 1995 03:24:00");

//Date and time, no time-zone
var birthday = new Date("1995-12-17T03:24:00");

//Only date as integer values
var birthday = new Date(1995,11,17);

//Date and time as integer values, no time-zone
var birthday = new Date(1995,11,17,3,24,0);

来源:MDN

Date()函数不接受时区作为参数。您认为时区参数有效的原因是因为它显示的是您输入的相同时区,但这是因为您处于同一时区。

您将Sat Apr 05 2014 19:00:00 GMT-0500 (CDT)作为日期输出(" 2014-04-07")的原因仅仅是因为您以不同的方式使用它。

new Date(parameters) 会根据传递的参数给出输出。

Date(parameters) 会将输出作为当前日期和时间,无论您传递哪个参数。

答案 1 :(得分:1)

在ES5之前,解析日期字符串完全取决于实现。 ES5指定了可能的浏览器支持的a version of ISO 8601,但不是全部。指定的格式仅支持Z时区(UTC),如果缺少时区,则采用UTC。缺少时区的支持是不一致的,有些实现会将字符串视为UTC,有些则视为本地。

要确定,您应该自己解析字符串,例如

/* Parse an ISO string with or without an offset
**   e.g. '2014-04-02T20:00:00-0600'
**        '2014-04-02T20:00:00Z'
**
** 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', treat as UTC date (per ECMA-262)
*/
function parseISOString(s) {
  var t = s.split(/\D+/g);
  var hasOffset = /\d{2}[-+]\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 ms = hasDecimalSeconds? t[6] : 0;
  var offMin, offSign, min;

  // If there's an offset, apply it to minutes to get a UTC time value
  if (hasOffset) {
    offMin = 60 * offset / 100 + offset % 100;
    offSign = /-\d{4}$/.test(s)? -1 : 1;
  }
  min = hasOffset? +t[4] - offMin * offSign : (t[4] || 0);

  // Return a date object based on UTC values
  return new Date(Date.UTC(t[0], --t[1], t[2], t[3]||0, min, t[5]||0, ms));
}

ISO 8601日期字符串应视为UTC(根据ECMA-262),因此如果您是UTC-0500,则:

new Date('2014-04-07'); // 2014-04-06T19:00:00-0500

OP中描述的行为表明主机不符合ECMA-262。进一步鼓励自己解析字符串。如果您希望将日期视为本地日期,则:

// Expect string in ISO 8601 format
// Offset is ignored, Date is created as local time
function parseLocalISODate(s) {
  s = s.split(/\D+/g);
  return new Date(s[0], --s[1], s[2],0,0,0,0);
}

在您的功能中,您可以执行以下操作:

var ds = data.feed.entry[i].gd$when[j].startTime;
var startDate = ds.length == 10? parseLocalISODate(ds) : parseISOString(ds);

另请注意,按照惯例,以大写字母开头的变量是为构造函数保留的,因此 startDate ,而不是 StartDate

答案 2 :(得分:0)

(我会添加评论,但我还没有50个代表)

查看内容

new Date()。getTimezoneOffset()

返回,我会期待一个很大的负值,这将是你问题的唯一合理解释。

我在过去的日期转换方面遇到了一些问题,特别是白天节省时区,并且为了解决这个问题,我总是将时间明确地设置为正午(上午12:00)。因为我认为你正在使用淘汰赛,你可以制作一个计算的观察者,它附加一个" T20:00:00.000-05:00"或适当的时区到所有"仅限#34;日期