[php] 두 날짜 사이의 일 수 찾기

PHP를 사용하여 두 날짜 사이의 일 수를 찾는 방법은 무엇입니까?



답변

$now = time(); // or your date as well
$your_date = strtotime("2010-01-31");
$datediff = $now - $your_date;

echo round($datediff / (60 * 60 * 24));


답변

를 사용하는 경우 PHP 5.3 >차이를 계산하는 가장 정확한 방법입니다.

$earlier = new DateTime("2010-07-06");
$later = new DateTime("2010-07-09");

$diff = $later->diff($earlier)->format("%a");


답변

PHP 버전 5.3부터는 새로운 날짜 / 시간 함수 가 추가되어 차이를 얻습니다.

$datetime1 = new DateTime("2010-06-20");

$datetime2 = new DateTime("2011-06-22");

$difference = $datetime1->diff($datetime2);

echo 'Difference: '.$difference->y.' years, '
                   .$difference->m.' months, '
                   .$difference->d.' days';

print_r($difference);

다음과 같은 결과 :

Difference: 1 years, 0 months, 2 days

DateInterval Object
(
    [y] => 1
    [m] => 0
    [d] => 2
    [h] => 0
    [i] => 0
    [s] => 0
    [invert] => 0
    [days] => 367
)

그것이 도움이되기를 바랍니다!


답변

날짜를 유닉스 타임 스탬프로 변환 한 다음 서로 빼십시오. 그러면 초 단위의 차이를 얻을 수 있으며 86400 (하루 초 단위)으로 나누어 해당 범위의 대략적인 일 수를 제공합니다.

날짜 형식 25.1.201001/25/2010또는 2010-01-25인 경우 strtotime함수를 사용할 수 있습니다 .

$start = strtotime('2010-01-25');
$end = strtotime('2010-02-20');

$days_between = ceil(abs($end - $start) / 86400);

를 사용하면 ceil일수를 다음 하루 종일까지 올림합니다. floor이 두 날짜 사이에 하루 종일을 얻으려면 대신 사용하십시오 .

날짜가 이미 유닉스 타임 스탬프 형식 인 경우 변환을 건너 뛰고 $days_between일부만 수행 할 수 있습니다 . 보다 이국적인 날짜 형식의 경우 올바른 구문을 얻기 위해 사용자 정의 구문 분석을 수행해야 할 수도 있습니다.


답변

TL; DR 은 UNIX 타임 스탬프를 사용 하지 않습니다 . 사용하지 마십시오time() . 당신이 경우에, 준비 의 98.0825 %의 신뢰성는 실패한다. DateTime (또는 Carbon)을 사용하십시오.

정답은 Saksham 굽타 (다른 답변도 정확)에 의해 주어진 하나입니다 :

$date1 = new DateTime('2010-07-06');
$date2 = new DateTime('2010-07-09');
$days  = $date2->diff($date1)->format('%a');

또는 절차 적으로 단일 라이너로 :

/**
 * Number of days between two dates.
 *
 * @param date $dt1    First date
 * @param date $dt2    Second date
 * @return int
 */
function daysBetween($dt1, $dt2) {
    return date_diff(
        date_create($dt2),
        date_create($dt1)
    )->format('%a');
}

주의 사항 : ‘% a’는 절대적인 일 수 를 나타내는 것 같습니다 . 부호있는 정수 (예 : 두 번째 날짜가 첫 번째 날짜 이전 인 경우 음수)로 표시하려면 ‘% r’접두사 (예 :)를 사용해야합니다 format('%r%a').


실제로 UNIX 타임 스탬프를 사용해야하는 경우 시간대를 GMT설정하여 아래에 설명 된 대부분 의 함정 을 피 하십시오.


긴 대답 : 24 * 60 * 60 (일명 86400)으로 나누는 것이 안전하지 않은 이유

유닉스 타임 스탬프를 사용하여 답변의 대부분 (86400는 일이를 변환하는)와 시나리오로 이어질 수 있습니다, 함께 넣어 두 가정을 만들 잘못된 결과미묘한 버그가 어려울 수 있습니다 추적하고, 며칠, 몇 주 또는 몇 달 후도를 발생 성공적인 배포. 솔루션이 작동하지 않는 것은 아닙니다. 작동합니다. 오늘. 그러나 내일 일을 멈출 수 있습니다.

첫 번째 실수는 “어제부터 몇 일이 지났는가?”라는 질문을 받았을 때 컴퓨터가 현재와 ​​”어제”로 표시된 순간 사이에 하루 종일 하루 가 지나지 않았다면 진실로 0 이라고 대답 할 수 있습니다 .

일반적으로 “일”을 UNIX 타임 스탬프로 변환 할 때 특정 요일 자정 의 타임 스탬프를 얻 습니다.

따라서 10 월 1 일과 10 월 15 일 자정 사이에 15 일이 경과했습니다. 그러나 10 월 15 일에서 10 월 1 일 13:00에서 14:55 사이에서 15 분에서 5 분뺀 시간 이 경과 floor()했으며 암시 적 정수 변환을 사용 하거나 수행하는 대부분의 솔루션 은 예상보다 하루가 덜보고됩니다 .

“Ymd H : i : s”는 몇일 전입니까? 잘못된 답변 을 얻을 입니다.

두 번째 실수는 하루를 86400 초와 동일시하는 것입니다. 이것은 거의 항상 사실입니다-그것은 종종 그렇지 않은 시간을 간과하기에 충분히 발생합니다. 그러나 일광 절약 시간 제가 시작될 때 2 년 연속 두 자정 사이의 거리 (초) 는 적어도 일년에 두 번은 반드시 86400 이 아닙니다. DST 경계를 넘어 두 날짜를 비교하면 잘못된 답을 얻을 수 있습니다.

따라서 모든 날짜 타임 스탬프를 고정 된 시간으로 강제하는 “해킹”을 사용하더라도 자정이라고 말합니다 (이것은 또한 시간-분-초가 아닌 일-월-년만 지정할 때 다양한 언어와 프레임 워크에 의해 암시 적으로 수행됩니다. MySQL과 같은 데이터베이스에서 DATE 유형의 동일한 일), 널리 사용되는 공식

 (unix_timestamp(DATE2) - unix_timestamp(DATE1)) / 86400

또는

 floor(time() - strtotime($somedate)) / 86400

DATE1과 DATE2가 연도의 동일한 DST 세그먼트에 있으면 17을 반환합니다. 그러나 17.042를 반환하고 더 나쁘게 16.958을 반환 할 수 있습니다. 그런 다음 floor () 또는 암시 적 잘림을 정수로 사용하면 17을 16으로 변환해야합니다. 다른 상황에서 “$ days> 17″과 같은 표현식 true은 경과 된 일 수가 계산됨을 나타내더라도 17.042 를 반환 합니다. 18입니다.

이러한 코드 플랫폼 전체에서 이식 가능하지 않기 때문에 상황이 더 나빠집니다 . 그 중 일부는 윤초를 적용하고 일부는 그렇지 않을 수 있기 때문 입니다. 이러한 플랫폼에 , 두 날짜 사이의 차이는 86400 만 86401, 아니면 86399.되지 않도록 12.99999 일 12 일 대신 13 개의 날짜를 고려 6 월 옆에 휴식 모든 테스트를 월 일 실제로 통과 코드 2015 년에 일한 것은 2017 년에 작동하지 않을 것입니다. 같은 날짜이며 윤년이 아닙니다. 그러나 2018-03-01과 2017-03-01 사이에 관심이있는 플랫폼 에서 365 대신 366 일이지나 2018 년을 윤년으로 만들 것입니다.

따라서 실제로 UNIX 타임 스탬프를 사용하려는 경우 :

  • round()기능을 현명하게 사용하십시오 floor().

  • 대안으로 D1-M1-YYY1과 D2-M2-YYY2의 차이를 계산하지 마십시오. 이 날짜는 실제로 D1-M1-YYY1 00:00:00 및 D2-M2-YYY2 00:00:00으로 간주됩니다. 오히려 D1-M1-YYY1 22:30:00과 D2-M2-YYY2 04:30:00 사이를 변환하십시오. 당신은 항상 약 20 시간의 나머지를 얻을 것 입니다. 이것은 21 시간 또는 19 시간, 아마도 18 시간, 55 분, 36 초가 될 수 있습니다. 문제 없어. 그것은 거기에 머물고 가까운 미래에 긍정적으로 남을 큰 마진 입니다. 이제floor() 안전으로 자를 수 있습니다 .

올바른 마법 상수, 반올림 잡든지 및 유지 보수 빚을 피하기 위해,하지만 솔루션이다

  • 시간 라이브러리 (Datetime, Carbon 등)를 사용하십시오. 자신의 롤을하지 마십시오

  • DST 경계, 윤년, 윤초 등의 일반적인 날짜와 일반적인 날짜를 사용하여 포괄적 인 테스트 사례 를 작성 합니다. 이상적으로 (datetime에 대한 호출은 빠릅니다 !) 문자열에서 순차적으로 조합하여 4 년 전체 (그리고 하루)에 해당하는 날짜를 생성하고 테스트되는 첫 날과 하루의 차이가 꾸준히 증가하는지 확인하십시오. 이것은 낮은 수준의 루틴과 도약 초에서 아무것도 변경하는 경우 보장합니다 수정 과시을 파괴하려고, 적어도 당신은 것 알고있다 .

  • 해당 테스트를 나머지 테스트 스위트와 함께 정기적으로 실행하십시오. 그들은 밀리 초의 문제이며 말 그대로 머리를 긁는 시간 을 절약 할 수 있습니다 .


솔루션이 무엇이든 테스트하십시오!

funcdiff아래 함수 는 실제 시나리오에서 솔루션 중 하나 (현상대로 받아 들여짐)를 구현합니다.

<?php
$tz         = 'Europe/Rome';
$yearFrom   = 1980;
$yearTo     = 2020;
$verbose    = false;

function funcdiff($date2, $date1) {
    $now        = strtotime($date2);
    $your_date  = strtotime($date1);
    $datediff   = $now - $your_date;
    return floor($datediff / (60 * 60 * 24));
}
########################################

date_default_timezone_set($tz);
$failures   = 0;
$tests      = 0;

$dom = array ( 0, 31, 28, 31, 30,
                  31, 30, 31, 31,
                  30, 31, 30, 31 );
(array_sum($dom) === 365) || die("Thirty days hath September...");
$last   = array();
for ($year = $yearFrom; $year < $yearTo; $year++) {
    $dom[2] = 28;
    // Apply leap year rules.
    if ($year % 4 === 0)   { $dom[2] = 29; }
    if ($year % 100 === 0) { $dom[2] = 28; }
    if ($year % 400 === 0) { $dom[2] = 29; }
    for ($month = 1; $month <= 12; $month ++) {
        for ($day = 1; $day <= $dom[$month]; $day++) {
            $date = sprintf("%04d-%02d-%02d", $year, $month, $day);
            if (count($last) === 7) {
                $tests ++;
                $diff = funcdiff($date, $test = array_shift($last));
                if ((double)$diff !== (double)7) {
                    $failures ++;
                    if ($verbose) {
                        print "There seem to be {$diff} days between {$date} and {$test}\n";
                    }
                }
            }
            $last[] = $date;
        }
    }
}

print "This function failed {$failures} of its {$tests} tests between {$yearFrom} and {$yearTo}.\n";

결과는

This function failed 280 of its 14603 tests

공포 이야기 : “시간 절약”의 비용

이것은 실제로 몇 달 전에 일어났습니다. 독창적 인 프로그래머는 악명 높은 “(MidnightOfDateB-MidnightOfDateA) / 86400″코드를 여러 곳에 연결하여 최대 30 초가 걸리는 계산에서 몇 마이크로 초를 절약하기로 결정했습니다. 그는 심지어 그것을 최적화하지 않은 최적화라는 것이 명백했으며, 최적화는 통합 테스트를 통과하고 코드에 몇 달 동안 숨어있었습니다.

이것은 몇몇 베스트셀러 세일즈맨의 임금을 계산하는 프로그램에서 일어 났으며, 그 중 최소는 전체 겸손한 5 인 프로그래머 팀이 모은 것보다 훨씬 더 무서워졌습니다. 몇 달 전 어느 날, 사소한 이유로 버그가 발생했습니다. 그 중 일부 는 하루 종일 팻 커미션이 부족했습니다. 그들은 분명히 즐겁게 하지 않았다 .

무한 악화, 그들은 (이미 거의) 믿음들이이 프로그램에 한 손실 되지 및 – 몰래 그들을 샤프트 설계 및 척하고 얻을 – 테스트 케이스와 완벽한 상세 코드 리뷰가 실행하고 평신도의 관점에서 주석 (플러스 많이 다음 주에 레드 카펫 처리).

내가 말할 수있는 것은 : 플러스 측면에서, 우리는 많은 기술적 부채를 제거하고 90 년대 스윙에서 COBOL 침입으로 귀환 된 몇 가지 스파게티 엉망을 다시 작성하고 리팩토링 할 수있었습니다. 이 프로그램은 의심 할 여지없이 더 나은 성능을 제공하며, 비린내가 생겼을 때 빠르게 제로화 할 수있는 더 많은 디버깅 정보가 있습니다. 나는이 마지막 것만으로도 가까운 미래를 위해 한 달에 1-2 일을 절약 할 수 있다고 추정합니다.

마이너스 측면에서 전체 brouhaha는 회사에 약 20 만 유로의 선불금을 지불했으며 의심 할 여지없이 일부 협상력 (따라서 더 많은 돈)을 지불했습니다.

“최적화”를 담당하는 사람은 1 년 전 재난 전에 직업이 바뀌었지만 여전히 손해 배상 소송을 제기했습니다. 그리고 그것은 “마지막 사람의 잘못”이라는 상층부와 잘 어울리지 않았습니다. 그것은 우리가 그 문제를 깨끗하게 정리하기위한 준비처럼 보였고, 결국 우리는 여전히 개집에 있습니다. 팀 중 하나가 종료 할 계획입니다.

백 개 중 아홉 번, “86400 핵”은 완벽하게 작동합니다. (예를 들어 PHP의 경우 strtotime()DST를 무시하고 10 월 마지막 토요일 자정과 다음 월요일 자정 사이에 정확히 2 * 24 * 60 * 60 초가 지났다는 사실 이 분명 하지 않더라도 … 그리고 두 가지 잘못이 행복하게 하나를 만들 것입니다).

신사 숙녀 여러분, 그렇지 않은 때는 예 였습니다 . 에어백 및 안전 벨트와 마찬가지로 또는 의 복잡성 (및 사용 편의성)이 실제로는 필요 하지 않습니다 . 그러나 당신 있는 날 (또는 당신이 이것에 대해 생각 했음을 증명해야 할 날 )은 밤에 도둑이 될 것입니다. 준비하십시오.DateTimeCarbon


답변

사용하기 쉬운 date_diff

$from=date_create(date('Y-m-d'));
$to=date_create("2013-03-15");
$diff=date_diff($to,$from);
print_r($diff);
echo $diff->format('%R%a days');

답변

객체 지향 스타일 :

$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days');

절차 적 스타일 :

$datetime1 = date_create('2009-10-11');
$datetime2 = date_create('2009-10-13');
$interval = date_diff($datetime1, $datetime2);
echo $interval->format('%R%a days');