JavaScript日期解析错误——对六月份的日期无法解析(??)

7

我有一些JavaScript代码,用于解析ISO-8601日期格式。但是,它在六月份的日期上出现了问题。然而七月和五月份的日期却能正常工作,这让我感到困惑。希望您能帮忙找出问题所在,因为我无法看出我在这里做错了什么。

函数定义(带错误)

function parseISO8601(timestamp)
{
  var regex = new RegExp("^([\\d]{4})-([\\d]{2})-([\\d]{2})T([\\d]{2}):([\\d]{2}):([\\d]{2})([\\+\\-])([\\d]{2}):([\\d]{2})$");
  var matches = regex.exec(timestamp);
  if(matches != null)
  {
    var offset = parseInt(matches[8], 10) * 60 + parseInt(matches[9], 10);
    if(matches[7] == "-")
      offset = -offset;

    var date = new Date();
    date.setUTCFullYear(parseInt(matches[1], 10));
    date.setUTCMonth(parseInt(matches[2], 10) - 1); //UPDATE - this is wrong
    date.setUTCDate(parseInt(matches[3], 10));
    date.setUTCHours(parseInt(matches[4], 10));
    date.setUTCMinutes(parseInt(matches[5], 10) - offset);
    date.setUTCSeconds(parseInt(matches[6], 10));
    date.setUTCMilliseconds(0);

    return date;
  }
  return null;
}

测试代码

alert(parseISO8601('2009-05-09T12:30:00-00:00').toUTCString());
alert(parseISO8601('2009-06-09T12:30:00-00:00').toUTCString());
alert(parseISO8601('2009-07-09T12:30:00-00:00').toUTCString());

输出

  • 2009年5月9日星期六 12:30:00 GMT
  • 2009年7月9日星期四 12:30:00 GMT
  • 2009年7月9日星期四 12:30:00 GMT

更新

感谢快速回答,问题在于日期对象最初是今天,即7月31日。当月份在改变日期之前被设置为6月时,它暂时成为了6月31日,然后被滚动到了7月1日。

我后来发现以下代码更加简洁,因为它一次性设置了所有日期属性:

function parseISO8601(timestamp)
{
  var regex = new RegExp("^([\\d]{4})-([\\d]{2})-([\\d]{2})T([\\d]{2}):([\\d]{2}):([\\d]{2})([\\+\\-])([\\d]{2}):([\\d]{2})$");
  var matches = regex.exec(timestamp);
  if(matches != null)
  {
    var offset = parseInt(matches[8], 10) * 60 + parseInt(matches[9], 10);
    if(matches[7] == "-")
      offset = -offset;

    return new Date(
      Date.UTC(
        parseInt(matches[1], 10),
        parseInt(matches[2], 10) - 1,
        parseInt(matches[3], 10),
        parseInt(matches[4], 10),
        parseInt(matches[5], 10),
        parseInt(matches[6], 10)
      ) - offset*60*1000
    );
  }
  return null;
}
5个回答

15

问题在于今天是7月31日。

当您设置:

var date = new Date();

然后date.getUTCDate()是31。当你调用date.setUTCMonth(5) (代表六月)时,你正在将date设置为6月31日。因为6月没有31号,JavaScript的Date对象把它变成了7月1日。所以在调用date.setUTCMonth(5)之后立即调用alert(date.getUTCMonth());,它将返回6

这并不是仅限于六月。对于任何其他没有31天的月份,在该月的31日使用此函数都会出现相同的问题。对于2月份的29日(非闰年)、30日或31日使用此函数也会返回错误的结果。

以覆盖由正确值替换任何溢出的方式调用setUTC*()应该可以解决这个问题:

var date = new Date();
date.setUTCMilliseconds(0);
date.setUTCSeconds(parseInt(matches[6], 10));
date.setUTCMinutes(parseInt(matches[5], 10) - offset);
date.setUTCHours(parseInt(matches[4], 10));
date.setUTCDate(parseInt(matches[3], 10));
date.setUTCMonth(parseInt(matches[2], 10) - 1);
date.setUTCFullYear(parseInt(matches[1], 10));

2
如果我将日期初始化为 new Date(0),那么是可以的(因为那是“1970-01-01T00:00:00-00:00”)。 - Kip
@Kip:是的,使用new Date(0)也可以解决这个问题,因为没有意外的月末滚动风险。 - Grant Wagner

5
日期对象从当前日期开始。今天是31日,设置2009-06-09会得到:
var date = new Date();     // Date is 2009-07-31
date.setUTCFullYear(2009); // Date is 2009-07-31
date.setUTCMonth(6 - 1);   // Date is 2009-06-31 = 2009-07-01
date.setUTCDate(9);        // Date is 2009-07-09

如果你在开始之前将日期设置为1号,那么你应该是安全的。


3

这是因为今天是7月31日。Grant解释了问题。我认为一个更简单的解决方案是将日期初始化为1月1日。

var date = new Date(2009,0,1,0,0,0);

0

看起来像是个bug?

C:\Documents and Settings\me>java org.mozilla.javascript.tools.shell.Main
Rhino 1.7 release 2 2009 03 22
js> date = new Date();
Fri Jul 31 2009 15:18:38 GMT-0400 (EDT)
js> date.setUTCMonth(5); date.toUTCString();
Wed, 01 Jul 2009 19:18:38 GMT
js> date.setUTCMonth(5); date.toUTCString();
Mon, 01 Jun 2009 19:18:38 GMT

编辑:算了吧,我想问题已经被更有经验的人回答了。


0

这是你更改日期的顺序。 日期最初为7月31日,因此月份设置失败,因为6月中没有31日。(实际上是滚动到7月1日。)

在设置完整年份后,请添加以下内容:

date.setYUTCDate(1);

这使得每个月都是有效的,这是本月的第一天。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接