首页 文章

查找两个日期之间的天数

提问于
浏览
522

如何使用PHP查找两个日期之间的天数?

26 回答

  • 62

    TL; DR不使用UNIX时间戳 . 不要使用时间() . 如果您这样做,请准备好98.0825%的可靠性使您失望 . 使用DateTime(或Carbon) .

    correct answer 是Saksham Gupta给出的那个(其他答案也是正确的):

    $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'似乎表示 absolute 天数 . 如果您希望它作为有符号整数,即当第二个日期在第一个日期之前为负时,则需要使用'%r'前缀(即 format('%r%a') ) .


    如果你真的必须使用UNIX时间戳, set the time zone to GMT 以避免下面详述的大部分陷阱 .


    答案:为什么除以24 * 60 * 60(又名86400)是不安全的

    大多数使用UNIX时间戳(以及86400将其转换为天数)的答案做出两个假设,这些假设放在一起可能导致 wrong resultssubtle bugs 可能难以跟踪的情况,并且在成功后几天,几周或几个月出现部署 . 它's not that the solution doesn'吨工作 - 它的工作原理 . 今天 . 但它明天可能会停止工作 .

    第一个错误是没有考虑到,当被问及时,如果在现在和"yesterday"指示的瞬间之间不到一整天,计算机可能如实回答 zero .

    通常在将"day"转换为UNIX时间戳时,获得的是该特定日期 midnight 的时间戳 .

    因此,在10月1日至10月15日的中午之间,已经过了十五天 . 但是在10月1日13:00到10月15日14:55之间,已经过了15天减去5分钟,并且大多数解决方案使用 floor() 或进行隐式整数转换 will report one day less than expected .

    那么,"how many days ago was Y-m-d H:i:s"?将产生 wrong answer .

    第二个错误是将一天等同于86400秒 . 这是 almost always 真实 - 它经常发生,往往忽视它没有的时间 . 但是,当夏令时发挥作用时,两个连续中午之间的距离以秒为单位,而不是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"这样的表达式将为17.042返回 true ,即使这表示经过的日期计数为18 .

    自从这些代码跨越平台以来,事情变得更加丑陋,因为some of them may apply leap seconds and some might not . 在那些平台上,两个日期之间的差异将不是86400而是86401,或者可能是86399.因此,在5月工作并且实际通过所有测试的代码将在明年6月中断,当时12.99999天被认为是12天而不是13天 . 两个日期在2015年工作的将在2017年不起作用 - 相同的日期,并且这两年都不是闰年 . 但是在2018-03-01和2017-03-01之间,在那些关心的平台上, 366 天将过去而不是365天,使2017年成为闰年 .

    所以如果你真的想使用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之间进行转换 . 你将总是得到大约二十个小时的剩余时间 . 这可能变成二十一小时或十九,也许十八小时,五十九分三十六秒 . 不管 . 这是一个巨大的利润,将留在那里,并在可预见的未来保持积极 . 现在你可以安全地使用 floor() 截断它 .

    但是,为避免魔术常数,四舍五入和维持债务, correct 解决方案是

    • 使用时间库(Datetime,Carbon,等等);不要自己动手

    使用真正邪恶的日期选择

    • comprehensive test cases - 跨越DST边界,跨越闰年,跨越闰秒等等,以及常见日期 . 理想情况下(调用datetime很快!)通过顺序组合它们来生成四年(和一天)的日期,并确保第一天和被测试日之间的差异稳定增加一 . 这将确保如果低级例程和闰秒修改中的任何更改尝试造成严重破坏,至少您会知道 .

    • 定期与测试套件的其余部分一起运行这些测试 . 它们只需几毫秒,可以节省数小时的头部刮伤 .


    无论您的解决方案是什么,请测试它!

    下面的函数 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 November...");
    $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秒的计算来节省几微秒 . 这是一个非常明显的优化,他甚至没有记录它,并且优化通过了集成测试并潜伏了几个月的代码,都没有被注意到 .

    这发生在一个计算几个最畅销的销售人员的工资的计划中,其中最少的一个比一个不起眼的五人程序员团队更有影响力 . 几个月前的某一天,由于原因很少,这个漏洞就出现了 - 而且其中一些人整整一天都在减薪 . 他们绝对没有被逗乐 .

    无限更糟糕的是,他们失去了他们在程序中所拥有的(已经非常少)的信念,而这些信念并非旨在暗中扼杀他们,并且假装 - 并且 obtained - 一个完整,详细的代码审查与测试用例运行并以外行的方式评论(加上很多)在接下来的几周内进行红地毯处理) .

    我能说什么:从好的方面来说,我们摆脱了大量的技术债务,并且能够重写和重构几个意大利面乱七八糟的东西,在90年代摇摆不定的情况下回到了COBOL的侵扰 . 毫无疑问,该程序现在运行得更好,并且有更多的调试信息可以在任何看起来很可疑时快速归零 . 我估计,在可预见的未来,这最后一件事每月可能会节省一到两个人日 .

    在负面方面,整个喧嚣使公司在前面花费了大约20万欧元 - 加上面子,加上无疑具有一些议价能力(因此还有更多的钱) .

    负责“优化”的人在灾难发生前一年前改变了工作,但仍然有人要求起诉他要求赔偿 . 它与上层人员的关系并不顺应,这是“最后一个人的错” - 它看起来像是我们清理此事的一个设置,最后,我们仍然在狗窝里其中一个团队正计划退出 .

    在百分之九十九中,"86400 hack"将完美无瑕地运作 . (例如在PHP中, strtotime() 将忽略DST并报告在十月的最后一个星期六和下一个星期一的中午之间,正好2 * 24 * 60 * 60秒已经过去,即使这显然不是真的..并且两个错误很乐意使一个人正确) .

    女士们,先生们,这是其中一个例子 . 与气囊和安全带一样,您可能永远不会真正需要 DateTimeCarbon 的复杂性(和易用性) . 但是你可能会(或者你必须要证明自己想到这一天的那一天)会在夜晚成为一个小偷 . 做好准备 .

  • -4

    如果你想回显开始和结束日期之间的所有日子,我想出了这个:

    $startdatum = $_POST['start']; // starting date
    $einddatum = $_POST['eind']; // end date
    
    $now = strtotime($startdatum);
    $your_date = strtotime($einddatum);
    $datediff = $your_date - $now;
    $number = floor($datediff/(60*60*24));
    
    for($i=0;$i <= $number; $i++)
    {
        echo date('d-m-Y' ,strtotime("+".$i." day"))."<br>";
    }
    
  • 16
    $start = '2013-09-08';
    $end = '2013-09-15';
    $diff = (strtotime($end)- strtotime($start))/24/3600; 
    echo $diff;
    
  • 779
    $now = time(); // or your date as well
    $your_date = strtotime("2010-01-01");
    $datediff = $now - $your_date;
    
    echo round($datediff / (60 * 60 * 24));
    
  • 0

    面向对象的风格:

    $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');
    
  • 8

    从PHP 5.3及更高版本开始,添加了new date/time functions以获得差异:

    $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
    )
    

    希望能帮助到你 !

  • 122

    PHP中两个日期之间的天数

    function dateDiff($date1, $date2)  //days find function
            { 
                $diff = strtotime($date2) - strtotime($date1); 
                return abs(round($diff / 86400)); 
            } 
           //start day
           $date1 = "11-10-2018";        
           // end day
           $date2 = "31-10-2018";    
           // call the days find fun store to variable 
           $dateDiff = dateDiff($date1, $date2); 
    
           echo "Difference between two dates: ". $dateDiff . " Days ";
    
  • 2

    易于使用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');
    
  • 3

    为了这个和类似的目的,我在我的作曲家项目中使用Carbon .

    它就像这样容易:

    $dt = Carbon::parse('2010-01-01');
    echo $dt->diffInDays(Carbon::now());
    
  • 1
    $early_start_date = date2sql($_POST['early_leave_date']);
    
    
    $date = new DateTime($early_start_date);
    $date->modify('+1 day');
    
    
    $date_a = new DateTime($early_start_date . ' ' . $_POST['start_hr'] . ':' . $_POST['start_mm']);
    $date_b = new DateTime($date->format('Y-m-d') . ' ' . $_POST['end_hr'] . ':' . $_POST['end_mm']);
    
    $interval = date_diff($date_a, $date_b);
    
    
    $time = $interval->format('%h:%i');
    $parsed = date_parse($time);
    $seconds = $parsed['hour'] * 3600 + $parsed['minute'] * 60;
    //        display_error($seconds);
    
    $second3 = $employee_information['shift'] * 60 * 60;
    
    if ($second3 < $seconds)
        display_error(_('Leave time can not be greater than shift time.Please try again........'));
        set_focus('start_hr');
        set_focus('end_hr');
        return FALSE;
    }
    
  • 1
    function get_daydiff($end_date,$today)
    {
        if($today=='')
        {
            $today=date('Y-m-d');
        }
        $str = floor(strtotime($end_date)/(60*60*24)) - floor(strtotime($today)/(60*60*24));
        return $str;
    }
    $d1 = "2018-12-31";
    $d2 = "2018-06-06";
    echo get_daydiff($d1, $d2);
    
  • 137

    这是我的改进版本,如果第二个参数通过,则显示1年(2)个月25天 .

    class App_Sandbox_String_Util {
        /**
         * Usage: App_Sandbox_String_Util::getDateDiff();
         * @param int $your_date timestamp
         * @param bool $hr human readable. e.g. 1 year(s) 2 day(s)
         * @see http://stackoverflow.com/questions/2040560/finding-the-number-of-days-between-two-dates
         * @see http://qSandbox.com
         */
        static public function getDateDiff($your_date, $hr = 0) {
            $now = time(); // or your date as well
            $datediff = $now - $your_date;
            $days = floor( $datediff / ( 3600 * 24 ) );
    
            $label = '';
    
            if ($hr) {
                if ($days >= 365) { // over a year
                    $years = floor($days / 365);
                    $label .= $years . ' Year(s)';
                    $days -= 365 * $years;
                }
    
                if ($days) {
                    $months = floor( $days / 30 );
                    $label .= ' ' . $months . ' Month(s)';
                    $days -= 30 * $months;
                }
    
                if ($days) {
                    $label .= ' ' . $days . ' day(s)';
                }
            } else {
                $label = $days;
            }
    
            return $label;
        }
    }
    
  • 5

    使用这个简单的功能 . 声明功能

    <?php
    function dateDiff($firstDate,$secondDate){
        $firstDate = strtotime($firstDate);
        $secondDate = strtotime($secondDate);
    
        $datediff = $firstDate - $secondDate;
        $output = round($datediff / (60 * 60 * 24));
        return $output;
    }
    ?>
    

    并在你想要的地方调用这个函数

    <?php
        echo dateDiff("2018-01-01","2018-12-31");    
    
    // OR
    
        $firstDate = "2018-01-01";
        $secondDate = "2018-01-01";
        echo dateDiff($firstDate,$secondDate);    
    ?>
    
  • 15

    如果您有以秒为单位的时间(I.E. unix时间戳),那么您可以简单地减去时间并除以86400(每天秒数)

  • 0

    用这个:)

    $days = (strtotime($endDate) - strtotime($startDate)) / (60 * 60 * 24);
    print $days;
    

    现在它有效

  • -1
    $datediff = floor(strtotime($date1)/(60*60*24)) - floor(strtotime($date2)/(60*60*24));
    

    并且,如果需要:

    $datediff=abs($datediff);
    
  • 0

    尝试使用Carbon

    $d1 = \Carbon\Carbon::now()->subDays(92);
    $d2 = \Carbon\Carbon::now()->subDays(10);
    $days_btw = $d1->diffInDays($d2);
    

    你也可以使用

    \Carbon\Carbon::parse('')
    

    使用给定的时间戳字符串创建Carbon日期的对象 .

  • 9

    如果您正在使用 PHP 5.3 > ,这是计算差异的最准确方法:

    $earlier = new DateTime("2010-07-06");
    $later = new DateTime("2010-07-09");
    
    $diff = $later->diff($earlier)->format("%a");
    
  • 0

    那么,所选答案不是最正确的答案,因为它会在UTC之外失败 . 根据时区(list),可能会有时间调整创建天数"without" 24小时,这将使计算(60 * 60 * 24)失败 .

    这是一个例子:

    date_default_timezone_set('europe/lisbon');
    $time1 = strtotime('2016-03-27');
    $time2 = strtotime('2016-03-29');
    echo floor( ($time2-$time1) /(60*60*24));
     ^-- the output will be **1**
    

    所以正确的解决方案是使用DateTime

    date_default_timezone_set('europe/lisbon');
    $date1 = new DateTime("2016-03-27");
    $date2 = new DateTime("2016-03-29");
    
    echo $date2->diff($date1)->format("%a");
     ^-- the output will be **2**
    
  • 0

    如果您使用的是MySql

    function daysSince($date, $date2){
    $q = "SELECT DATEDIFF('$date','$date2') AS days;";
    $result = execQ($q);
    $row = mysql_fetch_array($result,MYSQL_BOTH);
    return ($row[0]);
    

    }

    function execQ($q){
    $result = mysql_query( $q);
    if(!$result){echo ('Database error execQ' . mysql_error());echo $q;}    
    return $result;
    

    }

  • 5

    这个作品!

    $start = strtotime('2010-01-25');
    $end = strtotime('2010-02-20');
    
    $days_between = ceil(abs($end - $start) / 86400);
    
  • -1
    // Change this to the day in the future
    $day = 15;
    
    // Change this to the month in the future
    $month = 11;
    
    // Change this to the year in the future
    $year = 2012;
    
    // $days is the number of days between now and the date in the future
    $days = (int)((mktime (0,0,0,$month,$day,$year) - time(void))/86400);
    
    echo "There are $days days until $day/$month/$year";
    
  • 0
    function howManyDays($startDate,$endDate) {
    
        $date1  = strtotime($startDate." 0:00:00");
        $date2  = strtotime($endDate." 23:59:59");
        $res    =  (int)(($date2-$date1)/86400);        
    
    return $res;
    }
    
  • 447

    将您的日期转换为unix时间戳,然后从另一个中减去一个 . 这将为您提供以秒为单位的差异,您可以将其除以86400(一天中的秒数),以便为您提供该范围内的大致天数 .

    如果您的日期格式为 25.1.201001/25/20102010-01-25 ,则可以使用 strtotime 函数:

    $start = strtotime('2010-01-25');
    $end = strtotime('2010-02-20');
    
    $days_between = ceil(abs($end - $start) / 86400);
    

    使用 ceil 舍入到下一整天的天数 . 如果您想获得这两个日期之间的完整天数,请使用 floor .

    如果您的日期已经是unix时间戳格式,则可以跳过转换并执行 $days_between 部分 . 对于更奇特的日期格式,您可能需要进行一些自定义解析才能使其正确 .

  • 2

    您可以简单地找到日期

    <?php
    $start  = date_create('1988-08-10');
    $end    = date_create(); // Current time and date
    $diff   = date_diff( $start, $end );
    
    echo 'The difference is ';
    echo  $diff->y . ' years, ';
    echo  $diff->m . ' months, ';
    echo  $diff->d . ' days, ';
    echo  $diff->h . ' hours, ';
    echo  $diff->i . ' minutes, ';
    echo  $diff->s . ' seconds';
    // Output: The difference is 28 years, 5 months, 19 days, 20 hours, 34 minutes, 36 seconds
    
    echo 'The difference in days : ' . $diff->days;
    // Output: The difference in days : 10398
    
  • 0
    <?php
    $date1=date_create("2013-03-15");
    $date2=date_create("2013-12-12");
    $diff=date_diff($date1,$date2);
    echo $diff->format("%R%a days");
    ?>
    

    使用上面的代码非常简单 . 谢谢 .

相关问题