Regex per convalidare il formato data gg / mm / aaaa


172

Devo convalidare una stringa di date per il formato dd/mm/yyyycon un'espressione regolare.

Questa regex convalida dd/mm/yyyy, ma non le date non valide come 31/02/4500:

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

Che cos'è una regex valida per convalidare il dd/mm/yyyyformato con il supporto degli anni bisestili?


3
Penso che potrebbe aiutare se si imposta un'aspettativa accurata, poiché questa regex NON, in effetti, convalida correttamente gli anni bisestili; ad esempio, non c'è il 29 febbraio 2013, ma questa regex afferma che tale è valida: regexr.com?346fp
TML

7
Perché con Regex? Ci sono modi più semplici (e più precisi) ...
Dan Puzey,

2
Le espressioni regolari servono per abbinare modelli, non controllando valori numerici. Trova una stringa probabile con la regex, quindi controlla il suo valore numerico in qualunque sia la tua lingua host (PHP, qualunque cosa).
Andy Lester,

3
Questa risposta è stata aggiunta alle Domande frequenti sull'espressione regolare dello stack overflow , in "Attività di convalida comuni".
aliteralmind

4
@BurhanKhalid: ti sbagli. L'espressione regolare è lo strumento migliore per la convalida, poiché l'input HTML5 ha un attributo denominato patternche assume un'espressione regolare e i browser convalidano automaticamente contro la regex senza utilizzare alcun javascript. Semplicemente impostando una regex nell'attributo pattern!
timore

Risposte:


329

Il regex che hai incollato non convalida correttamente gli anni bisestili, ma ce n'è uno che fa lo stesso post . L'ho modificato per prendere dd/mm/yyyy, dd-mm-yyyyo 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})$

L'ho provato un po 'nel link fornito da Arun nella sua risposta e anche qui e sembra funzionare.

Modifica il 14 febbraio 2019: ho rimosso una virgola nella regex che consentiva date come 29-0,-11


9
Epica regex! Quanto facilmente potrebbe essere scambiato in base al formato? Ad esempio aaaa-mm-gg e mm-gg-aaaa. Ho provato a capirlo con questo in mente, ma va oltre le mie capacità di regex.
mrswadge,

7
Oltre a DD/MM/YYYYquesto, questa regex accetta anche DD/MM/YYche non sono sicuro che fosse nelle intenzioni iniziali del poster. Se non si desidera supportare "AA", rimuovere tutti i ?quantificatori opzionali .
user1485864

2
@PurveshDesai sostituisce ciascuno 0?con 0e rimuove anche l'ultima occorrenza di ?.
Ofir Luzon,

4
@MaraisRossouw, hai ragione, per un anno a 4 cifre, in realtà ci sono 3 ?che dovrebbero essere rimossi: sostituisci tutto (?:1[6-9]|[2-9]\d)?con (?:1[6-9]|[2-9]\d).
Ofir Luzon il

2
Scendendo solo per dire questo: WOW e ovviamente grazie
Jero Dungog

266

Ho esteso il regex dato da @Ofir Luzon per i formati gg-mmm-AAAA, gg / mmm / AAAA, gg.mmm.AAAA secondo le mie esigenze. Chiunque abbia lo stesso requisito può fare riferimento a questo

^(?:(?: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})$

e testato per alcuni casi di test qui http://regexr.com/39tr1 .

Per una migliore comprensione di questa espressione regolare consultare questa immagine: inserisci qui la descrizione dell'immagine


1
Sì, come lo hai generato? :)
Rasoio

L'ho generato online utilizzando alcuni siti Web e ora non ricordo nemmeno il sito Web da cui ho generato questa immagine. Aggiungerò il riferimento una volta che mi ricordo :)
Alok Chaudhary,

4
@ user3733831 8888è un anno possibile. Mi aspetto di vivere a quell'età.
Dan Nissenbaum,

1
Funziona alla grande anche per gli anni bisestili. Ho anche aggiunto il supporto per brevi nomi di mesi spagnoli.
Fer R

2
@AlokChaudhary, il diagramma è stato generato usando debuggex.com
Taha BASRI il

69

Avviso:

Il tuo regexp non funziona per anni che "sono multipli di 4 e 100, ma non di 400". Gli anni che superano quel test non sono anni bisestili. Ad esempio: 1900, 2100, 2200, 2300, 2500, ecc. In altre parole, mette tutti gli anni con il formato \ d \ d00 nella stessa classe di anni bisestili, che non è corretto. - Molto da imparare

Quindi funziona correttamente solo per [1901-2099] (Whew) 😊

dd / MM / yyyy:

Verifica se l'anno bisestile. Sono validi gli anni dal 1900 al 9999. Solo gg / MM / aaaa

(^(((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
Questa risposta funziona solo con gg / MM / aaaa. Pertanto, è la risposta giusta.
Rodrigo,

2
@SylvainB L'ho risolto
gdZeus

2
@gdZeus Grazie per la consegna, anche due anni dopo! Paura di pensare che una soluzione incompleta sia stata convalidata qui da così tanto tempo.
SylvainB,

Per renderlo più veloce è possibile rendere i gruppi non raggruppati. 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]) \ 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)) $
Matt Vukomanovic il

Suppongo di aver trovato un errore: 29/02/2100non esiste (2100 NON è un anno bisestile), ma è ancora accettato dal modello dato.
KnorxThieus,


12

Sospetto che quanto segue sia accurato come ci si può aspettare senza sapere quando le impostazioni internazionali dell'utente sono passate dai calendari giuliano a quello gregoriano.

Accetta '-', '/' o niente come separatori tra anno, mese e giorno, indipendentemente dall'ordine.

MMGGAAAA:

^(((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))$

aaaaMMgg:

^([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)$

Oltre all'ordine, questi sono tutti accurati rispetto al calendario giuliano (anno bisestile ogni quattro anni) fino al 1700, quando il calendario gregoriano si discosta da quello giuliano. Ha due problemi:

  1. Accetta l'anno 0000, che non esiste in molti, ma non in tutti gli standard. Si noti che ISO 8601 accetta l'anno 0000 (equivalente a 1 BCE).
  2. Non salta i 10-13 giorni persi quando è entrato in uso il Calendario Gregoriano. Questo tuttavia varia in base alla località. Ad esempio, la Chiesa cattolica romana saltò 10 giorni, dal 5 ottobre al 14 ottobre 1582, ma la Grecia (l'ultima a cambiare) saltò dal 16 al 28 febbraio 1923, 13 giorni, tenendo conto degli anni bisestili del 1700, 1800 e 1900.

Questo è stato testato rispetto all'implementazione del calendario Java dall'anno 0001 fino all'anno 9999 con l'unica discrepanza dei suddetti 10 giorni nel 1582.


La regex AAAAMMGG non corrisponde correttamente a [01 | 02 | 03 | 05 | 06 | 07 | 09 | 10 | 11 | 13 | 14 | 15] 00-02-29. Regex Corretto: ^([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)$. Testato con Python: repl.it/repls/DependentBestChapters
kpr

10

Per coloro che li guardano e si confondono completamente, ecco un estratto dal mio copione. Sfortunatamente, tutto ciò che fa è abbinare numeri validi in un input di data e il 31 febbraio verrà contrassegnato come valido, ma come molti hanno già detto, regex non è davvero lo strumento migliore per eseguire questo test.

Per abbinare una data nel formato 'aaaa-MM-gg hh: mm' (O in effetti nell'ordine che preferisci)

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;
}

Lo script precedente inizia creando un oggetto regex. Quindi trova tutti gli input il cui id corrisponde a un certo pattern e quindi li scorre attraverso. Non testare il primo input che trovo ( if (e > 0)).

Un po 'di spiegazione:

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

^significa inizio della partita, mentre $significa fine della partita.

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

\d+significa abbinare una singola o una sequenza contigua di numeri interi, quindi myhtml_element_with_id_56_datetimee myhtml_element_with_id_2_datetimecorrisponderà, ma myhtml_element_with_id_5a_datetimenon lo farà


8

Ecco un'altra versione di regex per abbinare uno dei seguenti formati di data e consentire di omettere gli zeri iniziali:

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

gli incontri:

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

Visualizzazione delle espressioni regolari

Debuggex Demo


4
non funziona se si dispone di 13/13/2000= Partite è vero
Andrei Krasutski

3
39/39/39 non è una data. Smetti di votare per questa risposta.
Warren Sergent,

6

Qui ne ho scritto uno per il dd/mm/yyyyquale il separatore può essere un -.,/intervallo dell'anno 0000-9999.

Si occupa degli anni bisestili ed è progettato per i sapori regex, che supportano lookaheads, catturando gruppi e backreferences. NON valido per tali d/m/yyyy. Se necessario, aggiungere ulteriori separatori a[-.,/]

^(?=\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}$

Test su regex101 ; come una stringa 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}$"

ha spiegato:

(?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

Vedi anche le domande frequenti su SO Regex ; Per favore fatemi sapere, se fallisce.


5

Ho trovato questo registro qui

^(((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))))$

Ciò convalida mm/dd/yyyycorrettamente il formato e le date valide (ma non m/d/yyyy).

Alcuni test


1
Funziona solo prima del 2014, è necessario modificare | 20 (0 [0-9] | 1 [0-4]))) in | 20 (0 [0-9] | 1 [0-9]))) per supportare fino 2019
Tony Dong,

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

convaliderà qualsiasi data tra 1900-2099


5

La seguente espressione è piacevole e facile da manipolare:

((((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])))

Si convalida secondo il formato MM / gg / AAAA e consente il supporto per l'anno bisestile dal 1960 al 2016. Se è necessario il supporto per l'anno bisestile esteso, è sufficiente manipolare questa parte dell'espressione:

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

Spero che questo ti abbia aiutato molto


3

Un'altra risposta che convalida il giorno (gg) a seconda del mese (mm) e dell'anno (aaaa) (vale a dire, convalida anche il 29 febbraio negli anni bisestili) e consente anni che vanno da 0001 a 9999 (0000 in un anno non valido secondo il Gregoriano calendario)

^(?:(?:(?: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
non convalida il 18/05/0017

1

Sto lavorando con un'API che accetta solo il formato MM / GG / AAAA. Non sono riuscito a trovare nessun altro post che abbia saltato anni e la risposta di Ofir , quindi l'ho modificato e lo sto postando di nuovo qui per chiunque ne avesse bisogno.

/^(?:(?:(?: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])))

convaliderà il MM/DD/YYYYformato con 1960a2028

se è necessario estendere il supporto per l'anno bisestile, aggiungere

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

anche questo è lavoro

^((((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])))

se puoi cambiare formato mm-dd-yyyypiuttosto che sostituirlo [/]per [-] controllare anche online http://regexr.com/


0

Per data MM / GG / AAAA è possibile utilizzare

^((((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}$

Verifica giorni e tarme adeguati.

Ricorda che puoi controllare la tua espressione regolare su

regex101

che consiglio :)

Divertiti!


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])))

questa regex convaliderà le date nel formato:

12-30-2016 (mm-gg-aaaa) o 12-3-2016 (mm-g-aaaa) o 1-3-2016 (md-aaaa) o 1-30-2016 (m-gg-aaaa)


0

So che è una risposta tangenziale alla domanda, ma se l' intenzione della domanda è "come convalidare una data?", Allora perché non provare a lasciare che il linguaggio di programmazione faccia tutto il duro lavoro (se stai usando un linguaggio che può)?

ad es. in php

$this_date_object = date_create($this_date);

if ($this_date_object == false )
    {

        // process the error

    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.