Ошибка синтаксического анализа даты в Javascript - не работает для дат в июне (??)

У меня есть 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());

Выход

  • Сб, 09 мая 2009 12:30:00 GMT
  • Чт, 09 июл 2009, 12:30:00 GMT
  • Чт, 09 июл 2009 12:30:00 GMT

Обновлять

Спасибо за быстрые ответы, проблема заключалась в том, что объект Date изначально был сегодня, то есть 31 июля. Когда месяц был установлен на июнь, до того, как я изменил день, это было временно 31 июня. , который был перенесен на 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;
}

person Kip    schedule 31.07.2009    source источник


Ответы (5)


Проблема в том, что сегодня 31 июля.

Когда вы устанавливаете:

var date = new Date();

Тогда date.getUTCDate() равно 31. Когда вы устанавливаете date.setUTCMonth(5) (для июня), вы устанавливаете date на 31 июня. Поскольку 31 июня нет, объект JavaScript Date превращает его в 1 июля. Так что сразу после установки вызова date.setUTCMonth(5), если вы alert(date.getUTCMonth());, это будет 6.

Это не уникально для июня. Использование вашей функции 31 числа любого месяца для любого другого месяца, в котором нет 31 дня, вызовет ту же проблему. Использование вашей функции 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));
person Grant Wagner    schedule 31.07.2009
comment
также, если я инициализирую дату как new Date(0), это нормально (поскольку это '1970-01-01T00: 00: 00-00: 00') - person Kip; 31.07.2009
comment
@ Кип: Да, использование new Date(0) также должно решить проблему, поскольку нет никакого риска непреднамеренного переноса позиций на конец месяца. - person Grant Wagner; 31.07.2009

Объект даты начинается с текущей даты. Сегодня это 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-е число до того, как начнете, то вы будете в безопасности.

person Greg    schedule 31.07.2009

Потому что сегодня 31 июля. Грант объяснил проблему. Вот что я считаю более простым решением. Инициализируйте дату 1 января.

var date = new Date(2009,0,1,0,0,0);
person Patrick McElhaney    schedule 31.07.2009

Это порядок, в котором вы меняете дату. Дата начинается 31 июля, поэтому набор месяца не выполняется, потому что 31 июля нет. (Собственно перекатывается на июл-1.)

После установки полного года добавьте это:

date.setYUTCDate(1);

Это делает его первым числом месяца, в котором действителен каждый месяц.

person Devon_C_Miller    schedule 31.07.2009

Похоже на ошибку?

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

РЕДАКТИРОВАТЬ: Неважно, я думаю. На вопрос уже ответил кто-то более знающий.

person Phil    schedule 31.07.2009