регулярное выражение javascript iso datetime - PullRequest
46 голосов
/ 29 июня 2010

есть ли у кого-нибудь хороший шаблон регулярных выражений для сопоставления iso datetime?

т.е.: 2010-06-15T00: 00: 00

Ответы [ 7 ]

82 голосов
/ 29 июня 2010

Для строгой, полной даты и времени, включая миллисекунды, за W3C принимает спецификацию .:

//-- Complete precision:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/

//-- No milliseconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)/

//-- No Seconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)/

//-- Putting it all together:
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/

.
Допускаются дополнительные вариантыпо факту ISO 8601: 2004 (E) doc :

/********************************************
**    No time-zone varients:
*/
//-- Complete precision:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+/

//-- No milliseconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d/

//-- No Seconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d/

//-- Putting it all together:
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d)/

ПРЕДУПРЕЖДЕНИЕ: все это быстро запутывается, и все еще допускает определенную чепуху, такую ​​как14 месяцКроме того, ISO 8601: 2004 (E) допускает несколько других вариантов.

.
"2010-06-15T00: 00: 00" недопустимо, поскольку не имеет обозначения часового пояса.

6 голосов
/ 12 августа 2016

Я переработал верхний ответ во что-то более краткое.Вместо того чтобы записывать каждый из трех необязательных шаблонов, элементы вкладываются как необязательные операторы.

/[+-]?\d{4}(-[01]\d(-[0-3]\d(T[0-2]\d:[0-5]\d:?([0-5]\d(\.\d+)?)?[+-][0-2]\d:[0-5]\dZ?)?)?)?/

Мне любопытно, есть ли недостатки у этого подхода?

Вы можете найти тесты для моего предлагаемого ответа здесь: http://regexr.com/3e0lh

5 голосов
/ 22 сентября 2017

Для сопоставления только с датой ISO, например 2017-09-22, вы можете использовать это регулярное выражение:

^\d{4}-([0]\d|1[0-2])-([0-2]\d|3[01])$

Он будет соответствовать любому числовому году, любому месяцу, указанному двумя цифрами в диапазоне 00-12, и любой дате, указанной двумя цифрами в диапазоне 00-31

5 голосов
/ 28 августа 2011

Вот регулярное выражение для проверки формата ISO 8601 date , включая високосные годы и короткие-длинные месяцы.Чтобы запустить это, вам нужно «игнорировать пробелы».Сжатая версия без пробелов находится в regexlib: http://regexlib.com/REDetails.aspx?regexp_id=3344

Это больше, чем ISO 8601 - это регулярное выражение заботится только о датах, но вы можете легко расширить его для поддержки проверки времени, что не так сложно.

Обновление: теперь это работает с javascript (без lookbehinds)

  ^(?:
      (?=
            [02468][048]00
            |[13579][26]00
            |[0-9][0-9]0[48]
            |[0-9][0-9][2468][048]
            |[0-9][0-9][13579][26]              
      )

      \d{4}

      (?:

        (-|)

        (?:

            (?:
                00[1-9]
                |0[1-9][0-9]
                |[1-2][0-9][0-9]
                |3[0-5][0-9]
                |36[0-6]
            )
            |
                (?:01|03|05|07|08|10|12)
                (?:
                  \1
                  (?:0[1-9]|[12][0-9]|3[01])
                )?            
            |
                (?:04|06|09|11)
                (?:
                  \1
                  (?:0[1-9]|[12][0-9]|30)
                )?            
            |
                02
                (?:
                  \1
                  (?:0[1-9]|[12][0-9])
                )?

            |
                W(?:0[1-9]|[1-4][0-9]|5[0-3])
                (?:
                  \1
                  [1-7]
                )?

        )            
      )?
  )$
  |
  ^(?:
      (?!
            [02468][048]00
            |[13579][26]00
            |[0-9][0-9]0[48]
            |[0-9][0-9][2468][048]
            |[0-9][0-9][13579][26]              
      )

      \d{4}

      (?:

        (-|)

        (?:

            (?:
                00[1-9]
                |0[1-9][0-9]
                |[1-2][0-9][0-9]
                |3[0-5][0-9]
                |36[0-5]
            )
            |
                (?:01|03|05|07|08|10|12)
                (?:
                  \2
                  (?:0[1-9]|[12][0-9]|3[01])
                )?

            |
                (?:04|06|09|11)
                (?:
                  \2
                  (?:0[1-9]|[12][0-9]|30)
                )?
            |
                (?:02)
                (?:
                  \2
                  (?:0[1-9]|1[0-9]|2[0-8])
                )?
            |
                W(?:0[1-9]|[1-4][0-9]|5[0-3])
                (?:
                  \2
                  [1-7]
                )?
       ) 
    )?
)$

Чтобы удовлетворить время, добавьте что-то подобное в смесь (из: http://underground.infovark.com/2008/07/22/iso-date-validation-regex/):

([T\s](([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)?(\15([0-5]\d))?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?
3 голосов
/ 30 июня 2010

Спецификация ISO 8601 допускает широкий спектр форматов даты. Существует посредственное объяснение того, как это сделать здесь . Существует довольно небольшое несоответствие между форматированием ввода даты в Javascript и форматированием ISO для простых дат, которые не задают часовые пояса, и его можно легко смягчить с помощью подстановки строк . Полностью поддерживать спецификацию ISO-8601 нетривиально.

Вот справочный пример, который я не гарантирую, чтобы быть полным, хотя он анализирует непостоянные даты из вышеупомянутой страницы Википедии.

Ниже приведен пример, и вы также можете увидеть его вывод на ideone . К сожалению, он не работает по спецификации, так как не реализует недели должным образом. Определение номера недели 01 в ISO-8601 является нетривиальным и требует некоторого просмотра календаря, чтобы определить, где начинается первая неделя и что именно это означает с точки зрения количества дней в указанном году. Возможно, это довольно легко исправить (я просто устал играть с ним).

function parseISODate (input) {
    var iso = /^(\d{4})(?:-?W(\d+)(?:-?(\d+)D?)?|(?:-(\d+))?-(\d+))(?:[T ](\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?)?(?:Z(-?\d*))?$/;

    var parts = input.match(iso);

    if (parts == null) {
        throw new Error("Invalid Date");
    }

    var year = Number(parts[1]);

    if (typeof parts[2] != "undefined") {
        /* Convert weeks to days, months 0 */
        var weeks = Number(parts[2]) - 1;
        var days  = Number(parts[3]);

        if (typeof days == "undefined") {
            days = 0;
        }

        days += weeks * 7;

        var months = 0;
    }
    else {
        if (typeof parts[4] != "undefined") {
            var months = Number(parts[4]) - 1;
        }
        else {
            /* it's an ordinal date... */
            var months = 0;
        }

        var days   = Number(parts[5]);
    }

    if (typeof parts[6] != "undefined" &&
        typeof parts[7] != "undefined")
    {
        var hours        = Number(parts[6]);
        var minutes      = Number(parts[7]);

        if (typeof parts[8] != "undefined") {
            var seconds      = Number(parts[8]);

            if (typeof parts[9] != "undefined") {
                var fractional   = Number(parts[9]);
                var milliseconds = fractional / 100;
            }
            else {
                var milliseconds = 0
            }
        }
        else {
            var seconds      = 0;
            var milliseconds = 0;
        }
    }
    else {
        var hours        = 0;
        var minutes      = 0;
        var seconds      = 0;
        var fractional   = 0;
        var milliseconds = 0;
    }

    if (typeof parts[10] != "undefined") {
        /* Timezone adjustment, offset the minutes appropriately */
        var localzone = -(new Date().getTimezoneOffset());
        var timezone  = parts[10] * 60;

        minutes = Number(minutes) + (timezone - localzone);
    }

    return new Date(year, months, days, hours, minutes, seconds, milliseconds);
}

print(parseISODate("2010-06-29T15:33:00Z-7"))
print(parseISODate("2010-06-29 06:14Z"))
print(parseISODate("2010-06-29T06:14Z"))
print(parseISODate("2010-06-29T06:14:30.2034Z"))
print(parseISODate("2010-W26-2"))
print(parseISODate("2010-180"))
1 голос
/ 06 марта 2019

с проверкой 02/29 с 1900 по 2999

 (((2000|2400|2800|(19|2[0-9](0[48]|[2468][048]|[13579][26])))-02-29)|(((19|2[0-9])[0-9]{2})-02-(0[1-9]|1[0-9]|2[0-8]))|(((19|2[0-9])[0-9]{2})-(0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01]))|(((19|2[0-9])[0-9]{2})-(0[469]|11)-(0[1-9]|[12][0-9]|30)))T([01][0-9]|[2][0-3]):[0-5][0-9]:[0-5][0-9]\.[0-9]{3}Z
0 голосов
/ 29 июня 2010

Не уверен, имеет ли это отношение к основной проблеме, которую вы пытаетесь решить, но вы можете передать строку даты ISO в качестве конструктора arg в Date () и получить объект из нее.Конструктор на самом деле очень гибок с точки зрения приведения строки в Date.

...