programing

PHP에서 모호하고 잘못된 날짜 시간을 탐지하는 방법은 무엇입니까?

javamemo 2023. 8. 18. 20:39
반응형

PHP에서 모호하고 잘못된 날짜 시간을 탐지하는 방법은 무엇입니까?

로컬과 거래할 때DateTime사용자가 제공한 값은 일광 절약 시간 전환으로 인해 유효하지 않거나 모호한 시간을 가질 수 있습니다.

다른 언어와 프레임워크에는 종종 다음과 같은 방법이 있습니다.isAmbiguous그리고.isValid시간대의 어떤 표현 위에.예를 들어.NET, 와 가 있습니다.

다른 많은 시간대 구현에는 이 문제를 해결하기 위한 유사한 방법 또는 기능이 있습니다.예를 들어 Python에서, Pytz 라이브러리는 다음과 같은 것을 던집니다.AmbiguousTimeError또는InvalidTimeError트랩할 수 있는 예외입니다.

PHP는 시간대 지원이 뛰어나지만, 이 문제를 해결할 수 있는 것을 찾을 수 없습니다.가장 가까운 것은 DateTimeZone::getTransitions입니다.그것은 원시 데이터를 제공하기 때문에, 저는 여기에 몇 가지 방법을 쓸 수 있다는 것을 알 수 있습니다.하지만 그들은 이미 어딘가에 존재할까요?그렇지 않다면, 누구나 좋은 구현을 제공할 수 있습니까?저는 그들이 다음과 같은 일을 하기를 기대합니다.

$tz = new DateTimeZone('America/New_York');
echo $tz->isValidTime(new DateTime('2013-03-10 02:00:00'));       # false
echo $tz->isAmbiguousTime(new DateTime('2013-11-03 01:00:00'));   # true

기존 구현에 대해 잘 알지 못하며 아직 이러한 고급 날짜/시간 기능을 사용할 필요가 없었기 때문에 클린룸 구현을 소개합니다.

질문에 설명된 구문을 활성화하기 위해 확장할 것입니다.DateTimeZone다음과 같이:

class DateTimeZoneEx extends DateTimeZone
{
    const MAX_DST_SHIFT = 7200; // let's be generous

    // DateTime instead of DateTimeInterface for PHP < 5.5
    public function isValidTime(DateTimeInterface $date);

    public function isAmbiguousTime(DateTimeInterface $date);
}

구현을 방해하는 세부 사항을 방해하지 않도록 하기 위해, 저는 다음과 같이 가정합니다.$date인수가 적절한 시간대로 생성되었습니다. 이는 질문에 주어진 예제 코드와 대조적입니다.

즉, 올바른 결과는 다음과 같이 생성되지 않습니다.

$tz = new DateTimeZoneEx('America/New_York');
echo $tz->isValidTime(new DateTime('2013-03-10 02:00:00'));

하지만 대신 이것에 의해:

$tz = new DateTimeZoneEx('America/New_York');
echo $tz->isValidTime(new DateTime('2013-03-10 02:00:00', $tz));

물론 그 이후로$tz개체에 이미 다음과 같이 알려져 있습니다.$this이 요구사항이 제거되도록 방법을 쉽게 확장할 수 있어야 합니다.어쨌든 인터페이스를 매우 사용자 친화적으로 만드는 것은 이 답변의 범위 밖입니다. 앞으로는 기술적인 세부 사항에 초점을 맞추겠습니다.

isValidTime

여기서는 관심 있는 날짜/시간을 기준으로 전환 사항이 있는지 확인하는 데 사용합니다.getTransitions하나 또는 두 개의 요소를 포함하는 배열을 반환합니다. 시간대 타임스탬프에 대한 시간대 상황은 항상 존재하며, 전환 직후에 전환이 발생하면 다른 요소가 존재합니다.MAX_DST_SHIFT두 번째 전환/세 번째 요소를 얻을 가능성이 없을 정도로 작습니다.

코드를 보겠습니다.

public function isValidTime(DateTime $date)
{
    $ts = $date->getTimestamp();
    $transitions = $this->getTransitions(
        $ts - self::MAX_DST_SHIFT,
        $ts + self::MAX_DST_SHIFT
    );

    if (count($transitions) == 1) {
        // No DST changes around here, so obviously $date is valid
        return true;
    }

    $shift = $transitions[1]['offset'] - $transitions[0]['offset'];

    if ($shift < 0) {
        // The clock moved backward, so obviously $date is valid
        // (although it might be ambiguous)
        return true;
    }

    $compare = new DateTime($date->format('Y-m-d H:i:s'), $this);

    return $compare->modify("$shift seconds")->getTimestamp() != $ts;
}

코드의 최종 지점은 PHP의 날짜 함수가 잘못된 날짜/시간에 대해 마치 벽시계 시간이 이동하지 않은 것처럼 타임스탬프를 계산한다는 사실에 따라 달라집니다.즉, 다음에 대해 계산된 타임스탬프2013-03-10 02:30:00그리고.2013-03-10 03:30:00뉴욕 시간대에 동일하게 적용될 것입니다.

이 사실을 활용하는 방법을 확인하는 것은 어렵지 않습니다. 새로운 솔루션을 구축하는 것입니다.DateTime입력과 동일한 인스턴스$date그런 다음 초 단위의 DST 시프트와 동일한 양의 월 클럭 시간 조건으로 이를 으로 이동합니다(이 조정을 수행하려면 DST를 고려하지 않는 것이 중요합니다).결과의 타임스탬프(여기서 DST 규칙이 실행됨)가 입력의 타임스탬프와 같으면 입력은 잘못된 날짜/시간입니다.

isAmbiguousTime

구현은 다음과 매우 유사합니다.isValidTime 정보만변경됩니다.

public function isAmbiguousTime(DateTime $date)
{
    $ts = $date->getTimestamp();
    $transitions = $this->getTransitions(
        $ts - self::MAX_DST_SHIFT, 
        $ts + self::MAX_DST_SHIFT);

    if (count($transitions) == 1) {
        return false;
    }

    $shift = $transitions[1]['offset'] - $transitions[0]['offset'];

    if ($shift > 0) {
        // The clock moved forward, so obviously $date is not ambiguous
        // (although it might be invalid)
        return false;
    }

    $shift = -$shift;
    $compare = new DateTime($date->format('Y-m-d H:i:s'), $this);
    return $compare->modify("$shift seconds")->getTimestamp() - $ts > $shift;
}

마지막 포인트는 PHP 날짜 함수의 다른 구현 세부 사항에 따라 달라집니다. 모호한 날짜/시간에 대한 타임스탬프를 생성하도록 요청받으면 PHP는 (절대 시간 용어로) 첫 번째 발생의 타임스탬프를 생성합니다.즉, 주어진 DST 변경에 대한 가장 최근의 모호한 시간과 가장 이른 모호하지 않은 시간의 타임스탬프가 DST 오프셋보다 큰 양만큼 다르다는 것을 의미합니다(구체적으로, 그 차이는 [] 범위에 있을 것입니다)offset + 1,2 * offset , , , , , , , , , , , , , , , , , , , , , .offset절대값)입니다.

은 "을 다시 앞으로 합니다.$date.

실행 중인 코드를 참조하십시오.

언급URL : https://stackoverflow.com/questions/59516906/how-can-i-check-if-a-datetime-is-valid-in-php-as-per-time-jumps-that-occur-for-d

반응형