查找两个日期之间的天数

时间:2010-01-11 08:06:57

标签: php

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

33 个答案:

答案 0 :(得分:829)

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

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

答案 1 :(得分:477)

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

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

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

答案 2 :(得分:146)

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

希望它有所帮助!

答案 3 :(得分:122)

将日期转换为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部分。对于更奇特的日期格式,您可能需要进行一些自定义解析才能使其正确。

答案 4 :(得分:81)

TL; DR 执行使用UNIX时间戳。 请勿使用time() 。如果你这样做,做好准备,如果它的98.0825%可靠性让你失望。使用DateTime(或Carbon)。

正确答案是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'似乎表示绝对天数。如果你想把它作为有符号整数,即当第二个日期在第一个日期之前时为负数,那么你需要使用'%r'前缀(即format('%r%a'))。

如果你真的必须使用UNIX时间戳,将时区设置为GMT ,以避免大多数下面详述的陷阱。

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

使用UNIX时间戳的大多数答案(以及86400将其转换为天数)会产生两个假设,这些假设会导致错误结果微妙错误可能难以跟踪,甚至在成功部署后数天,数周或数月出现。并不是解决方案不起作用 - 它有效。今天。但明天可能会停止工作。

第一个错误是没有考虑到当被问到时,"自昨天过去了多少天?",如果在当前和指示的瞬间之间,计算机可以如实回答 "昨天" 已经过了一整天

通常在转换" day"对于UNIX时间戳,获得的是该特定日期的午夜的时间戳。

因此,在10月1日至10月15日的中午之间,已经过了十五天。但是在10月1日13:00到10月15日14:55之间,十五天减去5分钟已经过去了,大多数使用floor()或进行隐式整数转换的解决方案都会报告比预期少一天

所以,"多少天前是Y-m-d H:我:s"?会产生错误答案

第二个错误是将一天等同于86400秒。这几乎总是为真 - 它经常发生,足以忽略它没有的时间。但是,当夏令时发挥作用时,两个连续中午之间的距离以秒为单位肯定不是86400,每年至少两次。比较DST边界的两个日期将得出错误的答案。

所以即使你使用" hack"强制所有日期时间戳到固定小时,比如午夜(当你只指定日 - 月 - 年而不是小时 - 分 - 秒时,这也是由各种语言和框架隐式完成的;同样在数据库中使用DATE类型如同MySQL),广泛使用的公式

 (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"即使这表示经过的日期计数为18,也会返回true 17.042。

由于此类代码不可移植跨平台,因此事情变得更加丑陋,因为some of them may apply leap seconds and some might not。在那些的平台上,两个日期之间的差异将不是86400而是86401,或者可能是86399.因此,在5月份工作并实际通过所有测试的代码将在明年6月中断,当时考虑129999天而不是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之间进行转换。您将始终获得大约20个小时的剩余时间。这可能变成二十一小时或十九,也许十八小时,五十九分三十六秒。不管。这是大幅度,它将留在那里并在可预见的未来保持积极态度。 现在您可以安全地使用floor()截断它。

正确的解决方案,为了避免魔术常数,四舍五入和维护债务,是

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

  • 使用真正邪恶的日期选择编写综合测试用例 - 跨越DST边界,跨越闰年,跨越闰秒等,以及常见日期。理想情况下(调用datetime fast !)生成整整四年' (并且有一天)值得约会,通过顺序组装它们,并确保第一天和被测试日之间的差异稳定增加一。这将确保如果低级例程中的任何更改和闰秒修复尝试造成严重破坏,至少您将知道

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

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

下面的函数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

恐怖故事:节省时间&#34;

的成本

这实际上发生在几个月前。一个聪明的程序员决定通过插入臭名昭着的&#34;(MidnightOfDateB-MidnightOfDateA)/ 86400&#34;计算,最多花费大约30秒来计算几微秒。几个地方的代码。这是一个非常明显的优化,他甚至没有记录它,并且优化通过了集成测试并潜伏了几个月的代码,都没有被注意到。

这是在一个计算几个最畅销的销售人员的工资的计划中发生的,其中最少的一个比一个简陋的五人程序员团队更有影响力。几个月前的某一天,由于重要的原因,这个漏洞已经发生了 - 而那些家伙的部分一整天都在减薪。他们肯定逗乐。

无限更糟糕的是,他们失去了他们在程序中的(已经非常少)的信念而不是被设计为偷偷摸摸地瞄准他们,假装 - 并且获得 - 一个完整的对测试用例进行了详细的代码审查,并以外行人的名义进行评论(在接下来的几周内加上大量的红地毯处理)。

我能说什么:从好的方面来说,我们摆脱了大量的技术债务,并且能够重写和重构几个意大利面条的碎片,这些碎片在摇摆的过程中听到了COBOL的侵扰。 20世纪90年代。毫无疑问,该程序现在运行得更好,并且有更多的调试信息可以在任何看起来很可疑时迅速归零。我估计,在可预见的未来,这最后一件事每月可能会节省一到两个人日。

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

负责&#34;优化&#34;在一年前,在灾难发生之前,他已经改变了工作,但仍然有人要求起诉他要求赔偿。它与上层人员并没有很好的关系,这是最后一个人的过错&#34; - 它似乎是我们清理此事的一个设置,最后,我们仍然在狗窝里,其中一个团队计划退出。

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

女士们,先生们,当它没有时,这是一个实例。与气囊和安全带一样,您可能永远不会真正需要DateTimeCarbon的复杂性(以及易用性)。但是当你可能的那一天(或者你必须证明你想到这一天的那一天)将会在夜晚成为一个小偷。做好准备。

答案 5 :(得分:16)

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

答案 6 :(得分:15)

面向对象的风格:

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

答案 7 :(得分:9)

使用此:)

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

现在可行了

答案 8 :(得分:9)

嗯,所选答案不是最正确的答案,因为它会在UTC之外失败。 根据时区(list),可能会有时间调整创建天数&#34;没有&#34; 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**

答案 9 :(得分:5)

$start = '2013-09-08';
$end = '2013-09-15';
$diff = (strtotime($end)- strtotime($start))/24/3600; 
echo $diff;

答案 10 :(得分:5)

我在我的作曲家项目中使用Carbon用于此目的和类似用途。

它就像这样容易:

$dt = Carbon::parse('2010-01-01');
echo $dt->diffInDays(Carbon::now());

答案 11 :(得分:3)

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

并且,如果需要:

$datediff=abs($datediff);

答案 12 :(得分:2)

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

答案 13 :(得分:2)

  

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 "; 

答案 14 :(得分:2)

计算两个日期之间的时差:

$date1=date_create("2013-03-15");
$date2=date_create("2013-12-12");

$diff=date_diff($date1,$date2);

echo $diff->format("%R%a days");

输出: +272天

date_diff()函数返回两个DateTime对象之间的差。

答案 15 :(得分:2)

您可以尝试以下代码:

$dt1 = strtotime("2019-12-12"); //Enter your first date
$dt2 = strtotime("12-12-2020"); //Enter your second date
echo abs(($dt1 - $dt2) / (60 * 60 * 24));

答案 16 :(得分:1)

查找两个日期之间的天差的最简单方法

$date1 = strtotime("2019-05-25"); 
$date2 = strtotime("2010-06-23");

$date_difference = $date2 - $date1;

$result =  round( $date_difference / (60 * 60 * 24) );

echo $result;

答案 17 :(得分:1)

您可以通过以下方式简单地找到日期

<?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

答案 18 :(得分:1)

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

$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>";
}

答案 19 :(得分:1)

function howManyDays($startDate,$endDate) {

    $date1  = strtotime($startDate." 0:00:00");
    $date2  = strtotime($endDate." 23:59:59");
    $res    =  (int)(($date2-$date1)/86400);        

return $res;
} 

答案 20 :(得分:0)

$diff = strtotime('2019-11-25') - strtotime('2019-11-10');
echo abs(round($diff / 86400));

答案 21 :(得分:0)

寻找所有答案,我编写了适用于所有PHP版本的通用函数。

if(!function_exists('date_between')) :
    function date_between($date_start, $date_end)
    {
        if(!$date_start || !$date_end) return 0;

        if( class_exists('DateTime') )
        {
            $date_start = new DateTime( $date_start );
            $date_end   = new DateTime( $date_end );
            return $date_end->diff($date_start)->format('%a');
        }
        else
        {           
            return abs( round( ( strtotime($date_start) - strtotime($date_end) ) / 86400 ) );
        }
    }
endif;

通常,我使用“ DateTime”来查找两个日期之间的日期。但是,如果由于某种原因,某些服务器设置未启用“ DateTime”,它将使用带有“ strtotime()”的简单(但不安全)计算。

答案 22 :(得分:0)

我阅读了所有以前的解决方案,没有一个使用PHP 5.3工具:DateTime :: Diff和DateInterval :: Days

DateInterval :: Days包含迄今为止正确的天数。不必创建一些特殊而怪异的东西。

/**
 * We suppose that PHP is configured in UTC
 * php.ini configuration:
 * [Date]
 * ; Defines the default timezone used by the date functions
 * ; http://php.net/date.timezone
 * date.timezone = UTC
 * @link http://php.net/date.timezone
 */

/**
 * getDaysBetween2Dates
 *
 * Return the difference of days between $date1 and $date2 ($date1 - $date2)
 * if $absolute parameter is false, the return value is negative if $date2 is after than $date1
 *
 * @param DateTime $date1
 * @param DateTime $date2
 * @param Boolean $absolute
 *            = true
 * @return integer
 */
function getDaysBetween2Dates(DateTime $date1, DateTime $date2, $absolute = true)
{
    $interval = $date2->diff($date1);
    // if we have to take in account the relative position (!$absolute) and the relative position is negative,
    // we return negatif value otherwise, we return the absolute value
    return (!$absolute and $interval->invert) ? - $interval->days : $interval->days;
}

echo '<h3>2020-03-01 - 2020-02-01: 29 days as it\'s a standard leap year</h3>';
echo getDaysBetween2Dates(new DateTime("2020-03-01"), new DateTime("2020-02-01"), false);

echo '<h3>1900-03-01 - 1900-02-01: 28 days as it\'s a "standard" century</h3>';
echo getDaysBetween2Dates(new DateTime("1900-03-01"), new DateTime("1900-02-01"), false);

echo '<h3>2000-03-01 - 2000-02-01: 29 days as it\'s a century multiple of 400: 2000=400x5</h3>';
echo getDaysBetween2Dates(new DateTime("2000-03-01"), new DateTime("2000-02-01"), false);

echo '<h3>2020-03-01 - 2020-04-01: -28 days as 2020-03-01 is before 2020-04-01</h3>';
echo getDaysBetween2Dates(new DateTime("2020-02-01"), new DateTime("2020-03-01"), false);

答案 23 :(得分:0)

我已经尝试了几乎所有给出的答案的方法。但是DateTime和date_create都没有在我所有的测试用例中给我正确的答案。专门测试2月和3月的日期或12月和1月的日期。

所以,我想到了混合解决方案。

public static function getMonthsDaysDiff($fromDate, $toDate, $includingEnding = false){
    $d1=new DateTime($fromDate);
    $d2=new DateTime($toDate);
    if($includingEnding === true){
        $d2 = $d2->modify('+1 day');
    }
    $diff = $d2->diff($d1);
    $months = (($diff->format('%y') * 12) + $diff->format('%m'));

    $lastSameDate = $d1->modify("+$months month");
    $days = date_diff(
        date_create($d2->format('Y-m-d')),
        date_create($lastSameDate->format('Y-m-d'))
    )->format('%a');

    $return = ['months' => $months,
        'days' => $days];
}

我知道,在性能上这相当昂贵。您也可以将其扩展为Years。

答案 24 :(得分:0)

使用此简单功能。声明功能

${application.version}

并在所需位置调用此函数

<?php
function dateDiff($firstDate,$secondDate){
    $firstDate = strtotime($firstDate);
    $secondDate = strtotime($secondDate);

    $datediff = $firstDate - $secondDate;
    $output = round($datediff / (60 * 60 * 24));
    return $output;
}
?>

答案 25 :(得分:0)

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

答案 26 :(得分: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");
?>

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

答案 27 :(得分:0)

$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;
}

答案 28 :(得分:0)

这是我的改进版本,如果第二个参数通过,则显示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;
    }
}

答案 29 :(得分:0)

    // 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";

答案 30 :(得分:-1)

尝试使用Carbon

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

您也可以使用

\Carbon\Carbon::parse('')

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

答案 31 :(得分:-1)

如果您使用的是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;

}

答案 32 :(得分:-4)

这有效!

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

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