[php] 날짜를 확인하는 PHP Regex는 YYYY-MM-DD 형식입니다.

최종 사용자가 입력 한 날짜가 YYYY-MM-DD인지 확인하려고합니다. 정규식은 내 장점이 아니었다. 내가 설정 한 preg_match ()에 대한 잘못된 반환 값을 계속 얻는다.

그래서 아래에 설명 된 정규식을 엉망으로 만들었다 고 가정합니다.

$date="2012-09-12";

if (preg_match("^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$",$date))
    {
        return true;
    }else{
        return false;
    }

이견있는 사람?



답변

이 시도.

$date="2012-09-12";

if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date)) {
    return true;
} else {
    return false;
}


답변

이를 위해 다른 메커니즘을 사용하는 것이 좋습니다.

다음과 같은 최신 솔루션 DateTime:

$dt = DateTime::createFromFormat("Y-m-d", $date);
return $dt !== false && !array_sum($dt::getLastErrors());

이것은 입력도 확인합니다 $dt !== false. 날짜가 지정된 형식으로 구문 분석 될 수 있는지 확인하고 array_sum트릭은 PHP가 “월 이동”을 수행하지 않도록하는 간결한 방법입니다 (예 : 1 월 32 일이 2 월 1 일이라고 가정). 자세한 내용은를 참조하십시오 DateTime::getLastErrors().

explodecheckdate다음을 사용한 구식 솔루션 :

list($y, $m, $d) = array_pad(explode('-', $date, 3), 3, 0);
return ctype_digit("$y$m$d") && checkdate($m, $d, $y);

이것은 입력이 유효한 날짜인지 확인합니다. 물론 정규식으로도 할 수 있지만 더 소란 스러울 것이며 2 월 29 일은 정규식으로 전혀 유효성을 검사 할 수 없습니다.

이 접근 방식의 단점은 어떤 상황에서도 알림을 표시하지 않고 가능한 모든 “나쁜”입력을 거부하도록 매우주의해야한다는 것입니다. 방법은 다음과 같습니다.

  • explode3 개의 토큰을 반환하도록 제한됩니다 (입력이 “1-2-3-4″인 $d경우 “3-4″가 됨).
  • ctype_digit 입력에 숫자가 아닌 문자 (대시 제외)가 포함되지 않았는지 확인하는 데 사용됩니다.
  • array_padcheckdate입력이 “1-2″인 list()경우 알림을 내 보내지 않도록 충분한 요소가 리턴되었는지 확인하기 위해 (실패 를 유발하는 기본값과 함께) 사용됩니다.

답변

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

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

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

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

dd / mm / yyyy :
/^(((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))))$/g

dd-mm-yyyy :
/^(((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))))$/g


답변

기준 :

4로 나눌 수있는 매년은 윤년입니다. 단, 400으로 나눌 수없는 한 100으로 나눌 수있는 경우는 예외입니다. 따라서 :

2004 - leap year - divisible by 4
1900 - not a leap year - divisible by 4, but also divisible by 100
2000 - leap year - divisible by 4, also divisible by 100, but divisible by 400

2 월은 윤년에 29 일, 윤년이 아닌 경우 28 일입니다.

4 월, 6 월, 9 월, 11 월 30 일

1 월, 3 월, 5 월, 7 월, 8 월, 10 월, 12 월 31 일

테스트:

다음 날짜는 모두 유효성 검사를 통과해야합니다.

1976-02-29
2000-02-29
2004-02-29
1999-01-31

다음 날짜는 모두 유효성 검사에 실패해야합니다.

2015-02-29
2015-04-31
1900-02-29
1999-01-32
2015-02-00

범위:

1000 년 1 월 1 일부터 2999 년 12 월 31 일까지의 날짜를 테스트 할 것입니다. 기술적으로 현재 사용되는 그레고리력은 대영 제국의 경우 1753 년, 유럽 국가의 경우 1600 년대의 여러 해에 사용되었지만 그것에 대해 걱정하십시오.

윤년 테스트를위한 정규식 :

400으로 나눌 수있는 연도 :

1200|1600|2000|2400|2800
can be shortened to:
(1[26]|2[048])00

if you wanted all years from 1AD to 9999 then this would do it:
(0[48]|[13579][26]|[2468][048])00
if you're happy with accepting 0000 as a valid year then it can be shortened:
([13579][26]|[02468][048])00

4로 나눌 수있는 연도 :

[12]\d([02468][048]|[13579][26])

100으로 나눌 수있는 연도 :

[12]\d00

100으로 나눌 수 없음 :

[12]\d([1-9]\d|\d[1-9])

100으로 나눌 수 있지만 400으로 나눌 수없는 연도 :

((1[1345789])|(2[1235679]))00

4로 나눌 수 있지만 100으로 나눌 수 없음 :

[12]\d([2468][048]|[13579][26]|0[48])

윤년 :

divisible by 400 or (divisible by 4 and not divisible by 100)
((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48])

4로 나눌 수 없습니다.

[12]\d([02468][1235679]|[13579][01345789])

윤년이 아닙니다.

Not divisible by 4 OR is divisible by 100 but not by 400
([12]\d([02468][1235679]|[13579][01345789]))|(((1[1345789])|(2[1235679]))00)

2 월을 제외한 유효한 월 및 일 (MM-DD) :

((01|03|05|07|08|10|12)-(0[1-9]|[12]\d|3[01]))|((04|06|09|11)-(0[1-9]|[12]\d|30))
shortened to:
((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30))

28 일이 포함 된 2 월 :

02-(0[1-9]|1\d|2[0-8])

29 일이 포함 된 2 월 :

02-(0[1-9]|[12]\d)

유효한 날짜 :

(leap year followed by (valid month-day-excluding-february OR 29-day-february))
OR
(non leap year followed by (valid month-day-excluding-february OR 28-day-february))

((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8]))))

그래서 거기에 YYYY-MM-DD 형식의 1000 년 1 월 1 일과 2999 년 12 월 31 일 사이의 날짜에 대한 정규식이 있습니다.

상당히 단축 될 수 있다고 생각하지만 다른 사람에게 맡기겠습니다.

유효한 모든 날짜와 일치합니다. 날짜가 하나만 있고 다른 것이없는 경우에만 유효하도록하려면 다음 ^( )$과 같이 래핑합니다 .

^(((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8])))))$

선택적 날짜 항목 (즉, 비어 있거나 유효한 날짜 일 수 있음)을 원하는 경우 다음을 추가하십시오. ^$| 과 같이 처음에 .

^$|^(((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8])))))$


답변

다음과 같이 만들 수 있습니다.

if (preg_match("/\d{4}\-\d{2}-\d{2}/", $date)) {
    echo 'true';
} else {
    echo 'false';
}

그러나 이것을 사용하는 것이 좋습니다.

$date = DateTime::createFromFormat('Y-m-d', $date);
if ($date) {
    echo $date -> format('Y-m-d');
}

이 경우 문자열보다 사용하기 더 쉬운 객체를 얻을 수 있습니다.


답변

나는 이것이 오래된 질문이라는 것을 알고 있습니다. 하지만 좋은 해결책이 있다고 생각합니다.

$date = "2016-02-21";
$format = "Y-m-d";

if(date($format, strtotime($date)) == date($date)) {
    echo "true";
} else {
    echo "false";
}

시도해 볼 수 있습니다. 날짜를 21.02.2016으로 변경하면 에코가 거짓입니다. 그 후 형식을 dmY로 변경하면 에코가 참입니다.

이 쉬운 코드를 사용하면 정규식에서 확인하지 않고도 사용되는 날짜 형식을 확인할 수 있습니다.

모든 경우에 테스트 할 사람이있을 수 있습니다. 하지만 내 생각은 일반적으로 유효하다고 생각합니다. 나에게는 논리적으로 보인다.


답변

checkdate php 함수와 함께 preg_match를 사용할 수 있습니다.

$date  = "2012-10-05";
$split = array();
if (preg_match ("/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/", $date, $split))
{
    return checkdate($split[2], $split[3], $split[1]);
}

return false;