Регулярное выражение для проверки формата даты дд / мм / гггг


172

Мне нужно проверить строку даты для формата dd/mm/yyyyс регулярным выражением.

Это регулярное выражение проверяет dd/mm/yyyy, но не допустимые даты, такие как 31/02/4500:

^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}$

Что такое действительное регулярное выражение для проверки dd/mm/yyyyформата с поддержкой високосного года?


3
Я думаю, что это может помочь, если вы установите точное ожидание, так как это регулярное выражение на самом деле НЕ корректно проверяет високосные годы; например, нет 29 февраля 2013 года, но это регулярное выражение утверждает, что такое действительно: regexr.com?346fp
TML

7
Почему с Regex? Есть более простые (и более точные) способы ...
Дэн Пьюзи

2
Регулярные выражения предназначены для сопоставления шаблонов, а не для проверки числовых значений. Найдите вероятную строку с регулярным выражением, затем проверьте ее числовое значение на любом языке вашего хоста (PHP, независимо от того).
Энди Лестер

3
Этот ответ был добавлен в FAQ по регулярному выражению переполнения стека в разделе «Общие задачи проверки».
aliteralmind

4
@BurhanKhalid: Вы не правы. Регулярное выражение - лучший инструмент для проверки, так как ввод HTML5 имеет атрибут с именем, patternкоторый принимает регулярное выражение, и браузеры автоматически проверяют соответствие регулярному выражению без использования какого-либо JavaScript. Просто установив регулярное выражение в атрибуте pattern!
благоговение

Ответы:


329

Вставленное вами регулярное выражение не проверяет правильность високосных лет, но есть в том же посте . Я изменил его, чтобы взять dd/mm/yyyy, dd-mm-yyyyили dd.mm.yyyy.

^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

Я проверил это немного в ссылке, которую Арун предоставил в своем ответе, а также здесь, и это, кажется, работает.

Изменить 14 февраля 2019 года: я удалил запятую, которая была в регулярном выражении, которая позволила даты как 29-0,-11


9
Эпическое регулярное выражение! Насколько легко это можно поменять в соответствии с форматом? Например, гггг-мм-дд и мм-дд-гггг. Я попытался понять это с учетом этого, но это выходит за рамки моих навыков регулярных выражений.
mrswadge

7
Кроме того DD/MM/YYYY, это регулярное выражение также принимает, DD/MM/YYчто я не уверен, что это было в первоначальном замысле автора. Если вы не хотите поддерживать YY, удалите все необязательные ?квантификаторы.
user1485864

2
@PurveshDesai заменить каждый 0?на 0, а также удалить последнее вхождение ?.
Офир Лусон

4
@MaraisRossouw, вы правы, для 4-х значного года фактически есть 3, ?которые нужно удалить: заменить все (?:1[6-9]|[2-9]\d)?на (?:1[6-9]|[2-9]\d).
Офир Лусон

2
Заходя просто сказать это: ВАУ и конечно спасибо
Джеро Дунгог

266

Я расширил регулярное выражение, данное @Ofir Luzon для форматов dd-mmm-YYYY, dd / mmm / YYYY, dd.mmm.YYYY в соответствии с моим требованием. Любой другой человек с таким же требованием может отослать это

^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)(?:0?2|(?:Feb))\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

и протестировано для некоторых тестов здесь http://regexr.com/39tr1 .

Для лучшего понимания этого регулярного выражения см. Это изображение: введите описание изображения здесь


1
Да, как вы это сгенерировали? :)
Бритва

Я сгенерировал его онлайн, используя какой-то сайт, и теперь я также не помню сайт, с которого я создал это изображение. Я добавлю ссылку, как только вспомню :)
Alok Chaudhary

4
@ user3733831 8888- возможный год. Я ожидаю дожить до этого возраста.
Дан Ниссенбаум

1
Прекрасно работает даже для високосных лет. Я также добавил поддержку коротких испанских названий месяцев.
Fer R

2
@AlokChaudhary, диаграмма была сгенерирована с помощью debuggex.com
Таха Басри

69

Примечание:

Ваше регулярное выражение не работает годами, которые «кратны 4 и 100, но не 400». Годы, прошедшие этот тест, не являются високосными. Например: 1900, 2100, 2200, 2300, 2500 и т. Д. Другими словами, все годы с форматом \ d \ d00 помещаются в один и тот же класс високосных лет, что неверно. - MuchToLearn

Так что это работает правильно только для [1901 - 2099] (Уф) 😊

дд / мм / гггг:

Проверяет, если високосный год. Годы с 1900 по 9999 действительны. Только дд / мм / гггг

(^(((0[1-9]|1[0-9]|2[0-8])[\/](0[1-9]|1[012]))|((29|30|31)[\/](0[13578]|1[02]))|((29|30)[\/](0[4,6,9]|11)))[\/](19|[2-9][0-9])\d\d$)|(^29[\/]02[\/](19|[2-9][0-9])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)$)

7
Этот ответ работает только с дд / мм / гггг. Следовательно, это правильный ответ.
Родриго

2
@SylvainB Я исправил это
gdZeus

2
@gdZeus Спасибо за доставку, даже через два года! Страшно подумать, что неполное решение стояло здесь проверенным так долго.
SylvainB

Чтобы сделать это быстрее, вы можете сделать группы не группирующимися. regexr.com/3esom ^ (? :(? :(? :( ?: 0 [1-9] | 1 [0-9] | 2 [0-8]) [\ /] (?: 0 [1- 9] | 1 [012])) | (:( ?: 29 |? 30 | 31) [\ /] (0 ?: [13578] | 1 [02])) | (:( ?: 29 |? 30 ) [\ /] (0 ?: [4,6,9] | 11))) [\ /] (?: 19 | [2-9] [0-9]) \ д \ г) | (?: 29 [\ /] 02 [\ /] (?: 19 | [2-9] [0-9]) (?: 00 | 04 | 08 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | 96)) $
Мэтт Вукоманович

Полагаю, я обнаружил ошибку: 29/02/2100не существует (2100 - это не високосный год), но все еще принимается по данной схеме.
KnorxThieus

17

попробуй это.

^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$

Вы можете легко проверить регулярное выражение на http://www.regular-expressions.info/javascriptexample.html .


2
это регулярное выражение не проверяет дату с месяцем, как 30-02-2001... в любом случае, спасибо за ответ :)
Nalaka526

12

Я подозреваю, что следующее настолько точно, насколько можно ожидать, не зная, когда языковой стандарт пользователя переключился с юлианского на григорианский календарь.

Он принимает либо '-', '/', либо ничего в качестве разделителей между годом, месяцем и днем, независимо от порядка.

ММДДГГГГ:

^(((0[13-9]|1[012])[-/]?(0[1-9]|[12][0-9]|30)|(0[13578]|1[02])[-/]?31|02[-/]?(0[1-9]|1[0-9]|2[0-8]))[-/]?[0-9]{4}|02[-/]?29[-/]?([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00))$

DDMMYYYY:

^(((0[1-9]|[12][0-9]|30)[-/]?(0[13-9]|1[012])|31[-/]?(0[13578]|1[02])|(0[1-9]|1[0-9]|2[0-8])[-/]?02)[-/]?[0-9]{4}|29[-/]?02[-/]?([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00))$

YYyyMmDd:

^([0-9]{4}[-/]?((0[13-9]|1[012])[-/]?(0[1-9]|[12][0-9]|30)|(0[13578]|1[02])[-/]?31|02[-/]?(0[1-9]|1[0-9]|2[0-8]))|([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00)[-/]?02[-/]?29)$

Кроме порядка, все они соответствуют юлианскому календарю (високосный год каждые четыре года) до 1700 года, когда григорианский календарь отличается от юлианского. У него есть две проблемы:

  1. Он принимает год 0000, которого нет во многих, но не во всех стандартах. Обратите внимание, что ISO 8601 принимает год 0000 (эквивалент 1 BCE).
  2. Это не пропускает 10-13 дней, которые были потеряны, когда вступил в силу григорианский календарь. Это зависит от местности, хотя. Например, Римско-католическая церковь пропустила 10 дней, с 5 октября по 14 октября 1582 года, но Греция (последняя сменила) пропустила 16 февраля по 28 октября 1923 года, 13 дней, с учетом високосных годов 1700 года, 1800 и 1900.

Это было проверено на основе реализации календаря Java с 0001 года по 9999 год, единственное расхождение - это 10 дней в 1582 году.


Регулярное выражение YYYYMMDD неправильно соответствует [01 | 02 | 03 | 05 | 06 | 07 | 09 | 10 | 11 | 13 | 14 | 15] 00-02-29. Исправлено регулярное выражение: ^([0-9]{4}[-/]?((0[13-9]|1[012])[-/]?(0[1-9]|[12][0-9]|30)|(0[13578]|1[02])[-/]?31|02[-/]?(0[1-9]|1[0-9]|2[0-8]))|([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048])00)[-/]?02[-/]?29)$. Протестировано с python: repl.it/repls/DependentBestChapters
kpr

10

Для тех, кто смотрит на это и полностью запутался, вот выдержка из моего сценария. К сожалению, все, что он делает, - это сопоставляет действительные числа при вводе даты и времени, и 31 февраля будет помечен как действительный, но, как многие говорили, регулярное выражение действительно не лучший инструмент для проведения этого теста.

Чтобы соответствовать дате в формате «гггг-ММ-дд чч: мм» (или в любом порядке, пожалуйста)

var dateerrors = false;
var yearReg = '(201[4-9]|202[0-9])';            ///< Allows a number between 2014 and 2029
var monthReg = '(0[1-9]|1[0-2])';               ///< Allows a number between 00 and 12
var dayReg = '(0[1-9]|1[0-9]|2[0-9]|3[0-1])';   ///< Allows a number between 00 and 31
var hourReg = '([0-1][0-9]|2[0-3])';            ///< Allows a number between 00 and 24
var minReg = '([0-5][0-9])';                    ///< Allows a number between 00 and 59
var reg = new RegExp('^' + yearReg + '-' + monthReg + '-' + dayReg + ' ' + hourReg + ':' + minReg + '$', 'g');
$('input').filter(function () {return this.id.match(/myhtml_element_with_id_\d+_datetime/);}).each(function (e) {
    if (e > 0) {
        // Don't test the first input. This will use the default
        var val = $(this).val();
        if (val && !val.trim().match(reg)) {
            dateerrors = true;
            return false;
        }
    }
});
if (dateerrors) {
    alert('You must enter a validate date in the format "yyyy-mm-dd HH:MM", e.g. 2019-12-31 19:30');
    return false;
}

Приведенный выше скрипт начинается с создания объекта регулярного выражения. Затем он находит все входные данные, чьи идентификаторы соответствуют определенному шаблону, и затем просматривает их. Я не проверяю первый ввод, который я нахожу (if (e > 0) ).

Немного объяснения:

var reg = new RegExp('^' + yearReg + '-' + monthReg + '-' + dayReg + ' ' + hourReg + ':' + minReg + '$', 'g');

^означает начало матча, тогда как $означает конец матча.

return this.id.match(/myhtml_element_with_id_\d+_datetime/);

\d+означает совпадение с единственной или непрерывной последовательностью целых чисел, поэтому myhtml_element_with_id_56_datetimeи myhtml_element_with_id_2_datetimeбудет совпадать, но myhtml_element_with_id_5a_datetimeне будет


8

Вот еще одна версия регулярного выражения, которая соответствует любому из следующих форматов даты и позволяет опускать начальные нули:

Regex: ^[0-3]?[0-9].[0-3]?[0-9].(?:[0-9]{2})?[0-9]{2}$

Спички:

1/1/11 or 1.1.11 or 1-1-11 : true 01/01/11 or 01.01.11 or 01-01-11 : true 01/01/2011 or 01.01.2011 or 01-01-2011 : true 01/1/2011 or 01.1.2011 or 01-1-2011 : true 1/11/2011 or 1.11.2011 or 1-11-2011 : true 1/11/11 or 1.11.11 or 1-11-11 : true 11/1/11 or 11.1.11 or 11-1-11 : true

Визуализация регулярных выражений

Debuggex Demo


4
не работает, если есть 13/13/2000= Матчи - это правда
Андрей Красуцкий

3
39/39/39 не дата. Пожалуйста, прекратите голосовать за этот ответ.
Уоррен

6

Здесь я написал один, dd/mm/yyyyгде разделитель может быть одного -.,/года диапазона 0000-9999.

Он имеет дело с високосными годами и разработан для регулярных выражений, которые поддерживают прогнозирование, захват групп и обратных ссылок. НЕ подходит для таких как d/m/yyyy. При необходимости добавьте дополнительные разделители в[-.,/]

^(?=\d{2}([-.,\/])\d{2}\1\d{4}$)(?:0[1-9]|1\d|[2][0-8]|29(?!.02.(?!(?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)\d{2}(?:[02468][048]|[13579][26])))|30(?!.02)|31(?=.(?:0[13578]|10|12))).(?:0[1-9]|1[012]).\d{4}$

Тест на регулярное выражение101 ; как строка Java:

"^(?=\\d{2}([-.,\\/])\\d{2}\\1\\d{4}$)(?:0[1-9]|1\\d|[2][0-8]|29(?!.02.(?!(?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)\\d{2}(?:[02468][048]|[13579][26])))|30(?!.02)|31(?=.(?:0[13578]|10|12))).(?:0[1-9]|1[012]).\\d{4}$"

пояснил:

(?x) # modifier x: free spacing mode (for comments)
     # verify date dd/mm/yyyy; possible separators: -.,/
     # valid year range: 0000-9999

^    # start anchor

# precheck xx-xx-xxxx,... add new separators here
(?=\d{2}([-.,\/])\d{2}\1\d{4}$)

(?:  # day-check: non caturing group

  # days 01-28
  0[1-9]|1\d|[2][0-8]| 

  # february 29d check for leap year: all 4y / 00 years: only each 400
  # 0400,0800,1200,1600,2000,...
  29
  (?!.02. # not if feb: if not ...
    (?!
      # 00 years: exclude !0 %400 years
      (?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)

      # 00,04,08,12,... 
      \d{2}(?:[02468][048]|[13579][26])
    )
  )|

  # d30 negative lookahead: february cannot have 30 days
  30(?!.02)|

  # d31 positive lookahead: month up to 31 days
  31(?=.(?:0[13578]|10|12))

) # eof day-check

# month 01-12
.(?:0[1-9]|1[012])

# year 0000-9999
.\d{4}

$ # end anchor

Также смотрите SO Regex FAQ ; Пожалуйста, дайте мне знать, если это не удастся.


5

Нашел этот рег экс здесь

^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$

Это проверяет формат mm/dd/yyyyи правильные даты правильно (но не m/d/yyyy).

Некоторые тесты


1
Работает только до 2014 года, необходимо изменить | 20 (0 [0-9] | 1 [0-4]))) на | 20 (0 [0-9] | 1 [0-9]))) для поддержки до 2019
Тони Донг

5
"^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((19|20)\\d\\d)$"

подтвердит любую дату между 1900-2099


5

Следующее выражение приятно и легко манипулировать:

((((0[13578]|1[02])(\/|-|.)(0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)(\/|-|.)(0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)((\/|-|.)(0[1-9]|1[0-9]|2[0-8]))))(\/|-|.)(19([6-9][0-9])|20(0[0-9]|1[0-4])))|((02)(\/|-|.)(29)(\/|-|.)(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26])))

Он проверяется в соответствии с форматом MM / dd / YYYY и допускает поддержку високосного года с 1960 по 2016 год. Если вам нужна расширенная поддержка високосного года, вам нужно только манипулировать этой частью выражения:

(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]))

Надеюсь, это вам очень помогло


3

Другой ответ, который проверяет день (dd) в зависимости от месяца (мм) и года (гггг) (т. Е. Также проверяет 29 февраля в високосные годы) и допускает годы в диапазоне от 0001 до 9999 (0000 в недействительном году по григорианскому языку). календарь)

^(?:(?:(?:0[1-9]|[12]\d|3[01])/(?:0[13578]|1[02])|(?:0[1-9]|[12]\d|30)/(?:0[469]|11)|(?:0[1-9]|1\d|2[0-8])/02)/(?!0000)\d{4}|(?:(?:0[1-9]|[12]\d)/02/(?:(?!0000)(?:[02468][048]|[13579][26])00|(?!..00)\d{2}(?:[02468][048]|[13579][26]))))$

1
не проверяет 18/05/0017

1

Я работаю с API, который принимает только формат MM / DD / YYYY. Я не мог найти ни одного другого поста, который прыгнул бы на годы так же хорошо, как и ответ Офира , поэтому я подправил его и опубликовал здесь для всех, кому это может понадобиться.

/^(?:(?:(?:0[13578]|1[02])(\/)31)\1|(?:(?:0[1,3-9]|1[0-2])(\/)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:02(\/)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\/)(?:0[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/

0
((((0[13578]|1[02])\/(0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)\/(0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)(\/(0[1-9]|1[0-9]|2[0-8]))))\/(19([6-9][0-9])|20([0-9][0-9])))|((02)\/(29)\/(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

будет проверять MM/DD/YYYYформат с 1960к2028

если вам нужно продлить поддержку високосного года, то добавьте

19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048]|3[26]|4[048])))

это тоже работа

^((((0[13578]|1[02])[/](0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)[/](0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)([/](0[1-9]|1[0-9]|2[0-8]))))[/](19([6-9][0-9])|20([0-9][0-9])))|((02)[/](29)[/](19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

если вы можете изменить формат, mm-dd-yyyyчем заменить, [/]чтобы [-] также проверить онлайн http://regexr.com/


0

Для даты ММ / ДД / ГГГГ вы можете использовать

^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$

Это проверить правильные дни и мотыльки.

Помните, что вы можете проверить свое регулярное выражение на

regex101

который я рекомендую :)

Радоваться, веселиться!


0
^(((([13578]|0[13578]|1[02])[-](0[1-9]|[1-9]|1[0-9]|2[0-9]|3[01]))|(([469]|0[469]|11)[-]([1-9]|1[0-9]|2[0-9]|3[0]))|((2|02)([-](0[1-9]|1[0-9]|2[0-8]))))[-](19([6-9][0-9])|20([0-9][0-9])))|((02)[-](29)[-](19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

это регулярное выражение будет проверять даты в формате:

12-30-2016 (мм-дд-гггг) или 12-3-2016 (мм-д-гггг) или 1-3-2016 (мд-гггг) или 1-30-2016 (м-дд-гггг)


0

Я знаю, что это тангенциальный ответ на вопрос, но если намерение на вопрос : «Как я могу проверить дату?», То почему бы не попробовать позволить язык программирования делать всю тяжелую работу (если вы используете язык, жестяная банка)?

например в php

$this_date_object = date_create($this_date);

if ($this_date_object == false )
    {

        // process the error

    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.