关于php:查找两个日期之间的天数


Finding the number of days between two dates

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


1
2
3
4
5
$now = time(); // or your date as well
$your_date = strtotime("2010-01-01");
$datediff = $now - $your_date;

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


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

1
2
3
4
$earlier = new DateTime("2010-07-06");
$later = new DateTime("2010-07-09");

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


从php 5.3及更高版本开始,添加了新的日期/时间函数以获得不同:

1
2
3
4
5
6
7
8
9
10
11
$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);

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
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
)

希望它有帮助!


将日期转换为Unix时间戳,然后将其中一个时间戳相减。这将给你以秒为单位的差额,除以86400(一天中的秒数),得到该范围内的大致天数。

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

1
2
3
4
$start = strtotime('2010-01-25');
$end = strtotime('2010-02-20');

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

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

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


tl;dr不使用unix时间戳。不要使用time()。如果你这样做了,准备好它98.0825%的可靠性失败。使用日期时间(或碳)。

正确答案是Saksham Gupta给出的答案(其他答案也正确):好的。

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

或者作为一个一行程序:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * 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日的午夜之间,已经过了15天。但是在10月1日的13:00到10月15日的14:55之间,已经过了15天减去5分钟,大多数使用floor()或进行隐式整数转换的解决方案将比预期少一天。好的。

那么,"几天前Y-M-D H:I:S"?会给出错误的答案。好的。

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

因此,即使使用"hack"将所有日期时间戳强制为一个固定的小时,比如说午夜(当您只指定日-月-年,而不指定时-分-秒时,各种语言和框架也会隐式地执行此操作;在数据库(如mysql)中,日期类型是相同的happens),这是广泛使用的公式好的。

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

或好的。

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

比如说,当date1和date2在一年中的DST段中时,将返回17;但它可能返回17.042,更糟的是,返回16.958。使用floor()或将任何隐式截断转换为整数,然后将原本应该是17的转换为16。在其他情况下,像"$days>17"这样的表达式将返回17.042的true,即使这表示经过的天数为18。好的。

而且事情变得更加糟糕,因为这样的代码不可跨平台移植,因为其中一些可能应用闰秒,而有些可能不适用。在这样的平台上,两个日期之间的差异将不是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之间转换。你将得到大约20小时的剩余时间。这可能会变成二十一小时或十九,也许十八小时,五十九分钟三十六秒。没关系。这是一个巨大的利润空间,将在可预见的未来保持积极。现在您可以用floor()安全地截断它。好的。

然而,正确的解决方案是,为了避免魔法常数,舍入Kludges和维护债务,是好的。

  • 使用时间库(datetime、carbon、随便什么);不要自己滚动好的。

  • 使用真正邪恶的日期选择编写全面的测试用例——跨越DST边界、跨越闰年、跨越闰秒等等,以及常见的日期。理想情况下(对日期时间的调用很快!)通过按顺序将数据串组合起来,生成四整年(和一天)的日期,并确保第一天和被测日期之间的差异稳步增加一天。这将确保,如果在低级别的例程和闰秒修复中发生任何更改,都会尝试造成破坏,至少您会知道。好的。

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

无论你的解决方案是什么,都要测试它!

下面的函数funcdiff实现了现实场景中的一种解决方案(实际上是公认的解决方案)。好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?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}
"
;
                    }
                }
            }
            $last[] = $date;
        }
    }
}

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

结果是,好的。

1
This function failed 280 of its 14603 tests

恐怖故事:节省时间的代价

这实际上发生在几个月前。一个聪明的程序员决定通过在几个地方插入臭名昭著的"(Midnightofdateb Midnightofdatea)/86400"代码,从最多花费30秒的计算中节省几微秒。很明显,一个优化甚至没有记录下来,优化通过了集成测试,潜伏在代码中几个月,都没有被注意到。好的。

这发生在一个计算几个最畅销的销售人员工资的程序中,其中最不重要的一个比一个简陋的五人程序员团队加在一起的影响力要大得多。几个月前的一天,由于一些无关紧要的原因,窃听器突然出现了——其中一些人在一整天的丰厚佣金中都被做空了。他们肯定不好笑。好的。

更糟糕的是,他们失去了(已经很少)对这个计划的信心,因为这个计划并没有被设计成秘密地欺骗他们,他们假装——并且获得了——一个完整的、详细的代码审查,测试案例以外行的方式运行和评论(加上接下来几周的大量红毯治疗)。好的。

我能说什么呢:从积极的方面来说,我们摆脱了许多技术债务,并且能够重写和重构几个在90年代的摇摆不定的COBOL感染中听到的意大利面混乱。毫无疑问,程序现在运行得更好了,当任何事情看起来可疑时,有更多的调试信息可以快速归零。我估计,在可预见的将来,仅仅是最后一件事,每个月就可以节省一两个人日。好的。

不利的一面是,整个布鲁哈公司的前期成本为20万欧元,加上毫无疑问的议价能力(因此,还有更多的钱)。好的。

负责"优化"的人一年前在灾难发生前换了工作,但仍有人说要起诉他要求赔偿损失。上流社会认为这是"最后一个家伙的错"并不是很好,这看起来像是一个让我们解决问题的安排,最后,我们仍然处于困境之中,其中一个团队计划退出。好的。

百分之九十九,"86400黑客"将无懈可击。(例如,在php中,strtotime()将忽略dst,并报告在10月最后一个星期六的午夜和下一个星期一的午夜之间,刚好经过了2*24*60*60秒,即使这显然不是真的……两个错误会使一个正确。好的。

女士们先生们,这是一个例子。与安全气囊和安全带一样,您可能永远不会真正需要DateTimeCarbon的复杂性(和易用性)。但当你可能(或当你必须证明你考虑这个的时候)的那天晚上会像小偷一样来。做好准备。好的。好啊。


易于使用的日期差异

1
2
3
4
5
$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');
  • 更多信息请访问:http://blog.innovssystems.com/php/get-number-days-between-two-dates-php


面向对象样式:

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

程序样式:

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

使用:

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

现在它起作用了


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

这里是一个例子:

1
2
3
4
5
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**

所以正确的解决方案是使用日期时间

1
2
3
4
5
6
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**


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


我在作曲项目中使用碳元素是为了这个和类似的目的。

就这么简单:

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

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

如果需要的话:

1
$datediff=abs($datediff);

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

1
2
3
4
5
6
$date1=date_create("2013-03-15");
$date2=date_create("2013-12-12");

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

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

输出:+ 272天

函数的作用是:返回两个日期时间对象之间的差。


number of days between two dates in PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
      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";


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


1
2
3
4
5
6
7
8
function howManyDays($startDate,$endDate) {

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

return $res;
}


你只需

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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

如果你想在开始日期和结束日期之间重复所有的日子,我想到了:

1
2
3
4
5
6
7
8
9
10
11
12
$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"))."";
}

使用这个简单的函数。Declare函数

1
2
3
4
5
6
7
8
9
10
<?php
function dateDiff($firstDate,$secondDate){
    $firstDate = strtotime($firstDate);
    $secondDate = strtotime($secondDate);

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

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

1
2
3
4
5
6
7
8
9
<?php
    echo dateDiff("2018-01-01","2018-12-31");    

// OR

    $firstDate ="2018-01-01";
    $secondDate ="2018-01-01";
    echo dateDiff($firstDate,$secondDate);    
?>


1
2
3
4
5
6
7
8
9
10
11
12
13
    // 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";

1
2
3
4
5
6
<?php
$date1=date_create("2013-03-15");
$date2=date_create("2013-12-12");
$diff=date_diff($date1,$date2);
echo $diff->format("%R%a days");
?>

使用上述代码非常简单。谢谢。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$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
2
3
4
5
6
7
8
9
10
11
12
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);


如果您使用的是MySQL

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

}

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

}


尝试使用碳

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

你也可以用

1
\Carbon\Carbon::parse('')

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


这是有效的!

1
2
3
4
$start = strtotime('2010-01-25');
$end = strtotime('2010-02-20');

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