ソースを参照

Allow dates before 1600 to be valid

Expand the valid date range to start at 0001 instead of 1600. This makes
validating historical dates simpler as they are now valid.

Fixes #13441
Mark Story 6 年 前
コミット
37ec1e1aac
2 ファイル変更35 行追加14 行削除
  1. 13 13
      src/Validation/Validation.php
  2. 22 1
      tests/TestCase/Validation/ValidationTest.php

+ 13 - 13
src/Validation/Validation.php

@@ -484,7 +484,7 @@ class Validation
      * Date validation, determines if the string passed is a valid date.
      * keys that expect full month, day and year will validate leap years.
      *
-     * Years are valid from 1800 to 2999.
+     * Years are valid from 0001 to 2999.
      *
      * ### Formats:
      *
@@ -522,29 +522,29 @@ class Validation
         }
         $month = '(0[123456789]|10|11|12)';
         $separator = '([- /.])';
-        $fourDigitYear = '(([1][8-9][0-9][0-9])|([2][0-9][0-9][0-9]))';
-        $twoDigitYear = '([0-9]{2})';
+        $fourDigitYear = '(?:[012]\d{3})';
+        $twoDigitYear = '(?:\d{2})';
         $year = '(?:' . $fourDigitYear . '|' . $twoDigitYear . ')';
 
         $regex['dmy'] = '%^(?:(?:31(\\/|-|\\.|\\x20)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)' .
-            $separator . '(?:0?[1,3-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29' .
-            $separator . '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])' .
-            $separator . '(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%';
+            $separator . '(?:0?[1,3-9]|1[0-2])\\2))' . $year . '$|^(?:29' .
+            $separator . '0?2\\3(?:(?:(?:[012]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])' .
+            $separator . '(?:(?:0?[1-9])|(?:1[0-2]))\\4' . $year . '$%';
 
         $regex['mdy'] = '%^(?:(?:(?:0?[13578]|1[02])(\\/|-|\\.|\\x20)31)\\1|(?:(?:0?[13-9]|1[0-2])' .
-            $separator . '(?:29|30)\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:0?2' . $separator . '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]))' .
-            $separator . '(?:0?[1-9]|1\\d|2[0-8])\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%';
+            $separator . '(?:29|30)\\2))' . $year . '$|^(?:0?2' . $separator . '29\\3(?:(?:(?:[012]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))' .
+            $separator . '(?:0?[1-9]|1\\d|2[0-8])\\4' . $year . '$%';
 
-        $regex['ymd'] = '%^(?:(?:(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))' .
-            $separator . '(?:0?2\\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\\d)?\\d{2})' .
+        $regex['ymd'] = '%^(?:(?:(?:(?:(?:[012]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))' .
+            $separator . '(?:0?2\\1(?:29)))|(?:' . $year .
             $separator . '(?:(?:(?:0?[13578]|1[02])\\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\\2(?:0?[1-9]|1\\d|2[0-8]))))$%';
 
-        $regex['dMy'] = '/^((31(?!\\ (Feb(ruary)?|Apr(il)?|June?|(Sep(?=\\b|t)t?|Nov)(ember)?)))|((30|29)(?!\\ Feb(ruary)?))|(29(?=\\ Feb(ruary)?\\ (((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])\\ (Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)\\ ((1[6-9]|[2-9]\\d)\\d{2})$/';
+        $regex['dMy'] = '/^((31(?!\\ (Feb(ruary)?|Apr(il)?|June?|(Sep(?=\\b|t)t?|Nov)(ember)?)))|((30|29)(?!\\ Feb(ruary)?))|(29(?=\\ Feb(ruary)?\\ ((([012]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)))))|(0?[1-9])|1\\d|2[0-8])\\ (Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)\\ ' . $fourDigitYear . '$/';
 
-        $regex['Mdy'] = '/^(?:(((Jan(uary)?|Ma(r(ch)?|y)|Jul(y)?|Aug(ust)?|Oct(ober)?|Dec(ember)?)\\ 31)|((Jan(uary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep)(tember)?|(Nov|Dec)(ember)?)\\ (0?[1-9]|([12]\\d)|30))|(Feb(ruary)?\\ (0?[1-9]|1\\d|2[0-8]|(29(?=,?\\ ((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)))))))\\,?\\ ((1[6-9]|[2-9]\\d)\\d{2}))$/';
+        $regex['Mdy'] = '/^(?:(((Jan(uary)?|Ma(r(ch)?|y)|Jul(y)?|Aug(ust)?|Oct(ober)?|Dec(ember)?)\\ 31)|((Jan(uary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep)(tember)?|(Nov|Dec)(ember)?)\\ (0?[1-9]|([12]\\d)|30))|(Feb(ruary)?\\ (0?[1-9]|1\\d|2[0-8]|(29(?=,?\\ (([012]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)))))))\\,?\\ ' . $fourDigitYear . ')$/';
 
         $regex['My'] = '%^(Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)' .
-            $separator . '((1[6-9]|[2-9]\\d)\\d{2})$%';
+            $separator . $fourDigitYear . '$%';
 
         $regex['my'] = '%^(' . $month . $separator . $year . ')$%';
         $regex['ym'] = '%^(' . $year . $separator . $month . ')$%';

+ 22 - 1
tests/TestCase/Validation/ValidationTest.php

@@ -943,10 +943,13 @@ class ValidationTest extends TestCase
      */
     public function testDateDdmmyyyy()
     {
+        $this->assertTrue(Validation::date('27-12-0001', ['dmy']));
         $this->assertTrue(Validation::date('27-12-2006', ['dmy']));
         $this->assertTrue(Validation::date('27.12.2006', ['dmy']));
         $this->assertTrue(Validation::date('27/12/2006', ['dmy']));
         $this->assertTrue(Validation::date('27 12 2006', ['dmy']));
+        $this->assertTrue(Validation::date('31-10-0001', ['dmy']));
+        $this->assertTrue(Validation::date('31-10-2006', ['dmy']));
         $this->assertFalse(Validation::date('00-00-0000', ['dmy']));
         $this->assertFalse(Validation::date('00.00.0000', ['dmy']));
         $this->assertFalse(Validation::date('00/00/0000', ['dmy']));
@@ -964,6 +967,7 @@ class ValidationTest extends TestCase
      */
     public function testDateDdmmyyyyLeapYear()
     {
+        $this->assertTrue(Validation::date('29-02-0004', ['dmy']));
         $this->assertTrue(Validation::date('29-02-2004', ['dmy']));
         $this->assertTrue(Validation::date('29.02.2004', ['dmy']));
         $this->assertTrue(Validation::date('29/02/2004', ['dmy']));
@@ -1057,6 +1061,7 @@ class ValidationTest extends TestCase
      */
     public function testDateDmyyyy()
     {
+        $this->assertTrue(Validation::date('1-1-0001', ['dmy']));
         $this->assertTrue(Validation::date('7-2-2006', ['dmy']));
         $this->assertTrue(Validation::date('7.2.2006', ['dmy']));
         $this->assertTrue(Validation::date('7/2/2006', ['dmy']));
@@ -1078,6 +1083,7 @@ class ValidationTest extends TestCase
      */
     public function testDateDmyyyyLeapYear()
     {
+        $this->assertTrue(Validation::date('29-2-0004', ['dmy']));
         $this->assertTrue(Validation::date('29-2-2004', ['dmy']));
         $this->assertTrue(Validation::date('29.2.2004', ['dmy']));
         $this->assertTrue(Validation::date('29/2/2004', ['dmy']));
@@ -1095,6 +1101,7 @@ class ValidationTest extends TestCase
      */
     public function testDateMmddyyyy()
     {
+        $this->assertTrue(Validation::date('01-01-0001', ['mdy']));
         $this->assertTrue(Validation::date('12-27-2006', ['mdy']));
         $this->assertTrue(Validation::date('12.27.2006', ['mdy']));
         $this->assertTrue(Validation::date('12/27/2006', ['mdy']));
@@ -1116,6 +1123,7 @@ class ValidationTest extends TestCase
      */
     public function testDateMmddyyyyLeapYear()
     {
+        $this->assertTrue(Validation::date('02-29-0004', ['mdy']));
         $this->assertTrue(Validation::date('02-29-2004', ['mdy']));
         $this->assertTrue(Validation::date('02.29.2004', ['mdy']));
         $this->assertTrue(Validation::date('02/29/2004', ['mdy']));
@@ -1209,6 +1217,7 @@ class ValidationTest extends TestCase
      */
     public function testDateMdyyyy()
     {
+        $this->assertTrue(Validation::date('1-1-0001', ['mdy']));
         $this->assertTrue(Validation::date('2-7-2006', ['mdy']));
         $this->assertTrue(Validation::date('2.7.2006', ['mdy']));
         $this->assertTrue(Validation::date('2/7/2006', ['mdy']));
@@ -1230,6 +1239,7 @@ class ValidationTest extends TestCase
      */
     public function testDateMdyyyyLeapYear()
     {
+        $this->assertTrue(Validation::date('2-29-0004', ['mdy']));
         $this->assertTrue(Validation::date('2-29-2004', ['mdy']));
         $this->assertTrue(Validation::date('2.29.2004', ['mdy']));
         $this->assertTrue(Validation::date('2/29/2004', ['mdy']));
@@ -1247,6 +1257,8 @@ class ValidationTest extends TestCase
      */
     public function testDateYyyymmdd()
     {
+        $this->assertTrue(Validation::date('0001-01-01', ['ymd']));
+        $this->assertTrue(Validation::date('0401-01-01', ['ymd']));
         $this->assertTrue(Validation::date('2006-12-27', ['ymd']));
         $this->assertTrue(Validation::date('2006.12.27', ['ymd']));
         $this->assertTrue(Validation::date('2006/12/27', ['ymd']));
@@ -1264,6 +1276,7 @@ class ValidationTest extends TestCase
      */
     public function testDateYyyymmddLeapYear()
     {
+        $this->assertTrue(Validation::date('0004-02-29', ['ymd']));
         $this->assertTrue(Validation::date('2004-02-29', ['ymd']));
         $this->assertTrue(Validation::date('2004.02.29', ['ymd']));
         $this->assertTrue(Validation::date('2004/02/29', ['ymd']));
@@ -1302,6 +1315,7 @@ class ValidationTest extends TestCase
      */
     public function testDateYymmddLeapYear()
     {
+        $this->assertTrue(Validation::date('0004-04-29', ['ymd']));
         $this->assertTrue(Validation::date('2004-02-29', ['ymd']));
         $this->assertTrue(Validation::date('2004.02.29', ['ymd']));
         $this->assertTrue(Validation::date('2004/02/29', ['ymd']));
@@ -1319,6 +1333,7 @@ class ValidationTest extends TestCase
      */
     public function testDateDdMMMMyyyy()
     {
+        $this->assertTrue(Validation::date('01 January 0001', ['dMy']));
         $this->assertTrue(Validation::date('27 December 2006', ['dMy']));
         $this->assertTrue(Validation::date('27 Dec 2006', ['dMy']));
         $this->assertFalse(Validation::date('2006 Dec 27', ['dMy']));
@@ -1332,6 +1347,7 @@ class ValidationTest extends TestCase
      */
     public function testDateDdMMMMyyyyLeapYear()
     {
+        $this->assertTrue(Validation::date('29 February 0004', ['dMy']));
         $this->assertTrue(Validation::date('29 February 2004', ['dMy']));
         $this->assertFalse(Validation::date('29 February 2006', ['dMy']));
     }
@@ -1343,6 +1359,7 @@ class ValidationTest extends TestCase
      */
     public function testDateMmmmDdyyyy()
     {
+        $this->assertTrue(Validation::date('January 01, 0001', ['Mdy']));
         $this->assertTrue(Validation::date('December 27, 2006', ['Mdy']));
         $this->assertTrue(Validation::date('Dec 27, 2006', ['Mdy']));
         $this->assertTrue(Validation::date('December 27 2006', ['Mdy']));
@@ -1359,6 +1376,7 @@ class ValidationTest extends TestCase
      */
     public function testDateMmmmDdyyyyLeapYear()
     {
+        $this->assertTrue(Validation::date('February 29, 0004', ['Mdy']));
         $this->assertTrue(Validation::date('February 29, 2004', ['Mdy']));
         $this->assertTrue(Validation::date('Feb 29, 2004', ['Mdy']));
         $this->assertTrue(Validation::date('February 29 2004', ['Mdy']));
@@ -1373,6 +1391,7 @@ class ValidationTest extends TestCase
      */
     public function testDateMy()
     {
+        $this->assertTrue(Validation::date('January 0001', ['My']));
         $this->assertTrue(Validation::date('December 2006', ['My']));
         $this->assertTrue(Validation::date('Dec 2006', ['My']));
         $this->assertTrue(Validation::date('December/2006', ['My']));
@@ -1386,6 +1405,7 @@ class ValidationTest extends TestCase
      */
     public function testDateMyNumeric()
     {
+        $this->assertTrue(Validation::date('01/0001', ['my']));
         $this->assertTrue(Validation::date('01/2006', ['my']));
         $this->assertTrue(Validation::date('12-2006', ['my']));
         $this->assertTrue(Validation::date('12.2006', ['my']));
@@ -1405,6 +1425,7 @@ class ValidationTest extends TestCase
      */
     public function testDateYmNumeric()
     {
+        $this->assertTrue(Validation::date('0001/01', ['ym']));
         $this->assertTrue(Validation::date('2006/12', ['ym']));
         $this->assertTrue(Validation::date('2006-12', ['ym']));
         $this->assertTrue(Validation::date('2006-12', ['ym']));
@@ -1429,6 +1450,7 @@ class ValidationTest extends TestCase
      */
     public function testDateY()
     {
+        $this->assertTrue(Validation::date('0001', ['y']));
         $this->assertTrue(Validation::date('1900', ['y']));
         $this->assertTrue(Validation::date('1984', ['y']));
         $this->assertTrue(Validation::date('2006', ['y']));
@@ -1439,7 +1461,6 @@ class ValidationTest extends TestCase
         $this->assertFalse(Validation::date('20009', ['y']));
         $this->assertFalse(Validation::date(' 2012', ['y']));
         $this->assertFalse(Validation::date('3000', ['y']));
-        $this->assertFalse(Validation::date('1799', ['y']));
     }
 
     /**