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
'programing' 카테고리의 다른 글
X-Powered-By: ASP와 같은 IIS 사용자 정의 헤더를 삭제하는 방법응답에서 NET? (0) | 2023.08.18 |
---|---|
Ajax를 사용하여 테이블 내용을 새로 고친 후 데이터 테이블을 다시 그리시겠습니까? (0) | 2023.08.18 |
Node.js를 Maria에 연결할 수 없습니다.DB (0) | 2023.08.18 |
두 열의 빠른 비교 방법 (0) | 2023.08.18 |
PowerShell에서 CSV로 내보낼 때 열 순서를 지정하려면 어떻게 해야 합니까? (0) | 2023.08.18 |