找出两个日期之间的天数。

时间:2021-01-11 21:33:08

How to find number of days between two dates using PHP?

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

22 个解决方案

#1


700  

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

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

#2


406  

If you're using PHP 5.3 >, this is by far the most accurate way of calculating the difference:

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

$date1 = new DateTime("2010-07-06");
$date2 = new DateTime("2010-07-09");

$diff = $date2->diff($date1)->format("%a");

#3


127  

From PHP Version 5.3 and up, new date/time functions have been added to get difference:

在PHP版本5.3和up中,添加了新的日期/时间函数来获得差异:

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

Result as below:

结果如下:

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
)

Hope it helps !

希望它可以帮助!

#4


122  

Convert your dates to unix timestamps, then substract one from the another. That will give you the difference in seconds, which you divide by 86400 (amount of seconds in a day) to give you an approximate amount of days in that range.

将您的日期转换为unix时间戳,然后从另一个中减去一个。这将给你带来不同的秒数,你可以用86400(一天内的秒数)来给你一个大致的天数。

If your dates are in format 25.1.2010, 01/25/2010 or 2010-01-25, you can use the strtotime function:

如果你的日期格式为25.1.2010,01/25/2010或2010-01-25,你可以使用strtotime函数:

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

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

Using ceil rounds the amount of days up to the next full day. Use floor instead if you want to get the amount of full days between those two dates.

使用ceil可以将几天的时间延长到下一个全天。如果你想在这两个日期之间获得足够的天数,可以使用地板。

If your dates are already in unix timestamp format, you can skip the converting and just do the $days_between part. For more exotic date formats, you might have to do some custom parsing to get it right.

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

#5


37  

TL;DR do not use UNIX timestamps. Do not use time(). If you do, be prepared should its 98.0825% reliability fail you. Use DateTime (or Carbon).

The correct answer is the one given by Saksham Gupta (other answers are also correct):

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

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

Or procedurally as a one-liner:

或者从程序上说,

/**
 * 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');
}

If you really must use UNIX timestamps, set the time zone to GMT to avoid most of the pitfalls detailed below.

如果您确实必须使用UNIX时间戳,请将时区设置为GMT,以避免下面详细介绍的大多数陷阱。


Long answer

Most of the answers using UNIX timestamps make two assumptions that, put together, can lead to scenarios with wrong results and subtle bugs that may be difficult to track, and arise even days, weeks or months after a successful deployment.

使用UNIX时间戳的大多数答案都有两个假设,它们组合在一起,可能导致错误的结果和难以跟踪的微妙错误,甚至在成功部署之后的几天、几周或几个月就会出现。

First mistake is not considering that when asked, "How many days passed since yesterday?", a computer might truthfully answer zero if between the present and the instant indicated by "yesterday" less than one whole day has passed.

第一个错误是,当被问到:“从昨天开始有多少天了?”如果在“昨天”和“昨天”之间的时间间隔不到一天,计算机可能会如实回答“0”。

Usually when converting a "day" to a UNIX timestamp, what is obtained is the timestamp for the midnight of that particular day.

通常,在将“day”转换为UNIX时间戳时,所得到的是该特定日期午夜的时间戳。

So between the midnights of October 1st and October 15th, fifteen days have elapsed. But between 13:00 of October 1st and 14:55 of October 15th, fifteen days minus 5 minutes have elapsed, and most solutions using floor() or doing implicit integer conversion will report one day less than expected.

所以在10月1日和10月15日的午夜之间,已经过去了15天。但是在10月1日13点到10月15日的14:55之间,15天减去5分钟已经过去了,大多数使用floor()或进行隐式整数转换的解决方案将比预期的少一天报告。

So, "how many days ago was Y-m-d H:i:s"? will yield the wrong answer.

那么,“多少天以前是Y-m-d H: s”?会产生错误的答案。

The second mistake is equating one day to 86400 seconds. This is almost always true - it happens often enough to overlook the times it doesn't. But the distance in seconds between two consecutive midnights is surely not 86400 at least twice a year when daylight saving time comes into play. Comparing two dates across a DST boundary will again yield the wrong answer.

第二个错误是将一天等同于86400秒。这几乎总是正确的——它经常发生,以至于忽略了它所没有的时间。但是,在两个连续的午夜之间的间隔时间肯定不是86400,至少是在夏令时开始时的两倍。将两个日期在DST边界上进行比较将再次产生错误的答案。

So even if you use the "hack" of forcing all date timestamps to a fixed hour, say midnight (this is also done implicitly by various languages and frameworks when you only specify day-month-year and not also hour-minute-second), the widely used formula

因此,即使你使用“hack”将所有日期时间戳强制到一个固定的时间,比如午夜(也可以通过各种语言和框架隐式地完成,当你只指定日- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -。

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

or

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

will return, say, 17 when DATE1 and DATE2 are in the same DST segment of the year; but it may return 17.042, and worse still, 16.958. The use of floor() or any implicit truncation to integer will then convert what should have been a 17 to a 16. In other circumstances, expressions like "$days > 17" will return true for 17.042 even if this indicates that the elapsed day count is 18.

当DATE1和DATE2在一年中的DST段时,将返回17;但它可能会返回17.042,更糟糕的是,16.958。使用floor()或任何隐式截断的整数将会转换为17到16的值。在其他情况下,像“$days > 17”这样的表达式将返回true,即使这表示经过的天数是18。

And things grow even uglier since such code is not portable across platforms, because some of them may apply leap seconds and some might not. On those platforms that do, the difference between two dates will not be 86400 but 86401, or maybe 86399. So code that worked in May and actually passed all tests will break next June when 12.99999 days are considered 12 days instead of 13. Two dates that worked in 2015 will not work in 2017 -- the same dates, and neither year is a leap year. But between 2018-03-01 and 2017-03-01, on those platforms that care, 366 days will have passed instead of 365, making 2017 a leap year.

而且,由于这些代码不能移植到平台上,因此事情变得更加糟糕,因为其中一些代码可能会应用闰秒,而有些则可能不会。在这些平台上,两个日期的区别不是86400,而是86401,或者可能是86399。因此,在5月份工作的代码实际上通过了所有测试,在明年6月,12.99999天被认为是12天,而不是13天。在2015年工作的两个日期将不会在2017年完成——同样的日期,而不是闰年。但在2013 -03-01和2017-03-01之间,在那些关心的平台上,366天将取代365天,使2017年成为闰年。

So if you really want to use UNIX timestamps:

所以如果你真的想使用UNIX时间戳:

  • use round() function wisely, not floor().

    明智地使用round()函数,而不是floor()。

  • as an alternative, do not calculate differences between D1-M1-YYY1 and D2-M2-YYY2. Those dates will be really considered as D1-M1-YYY1 00:00:00 and D2-M2-YYY2 00:00:00. Rather, convert between D1-M1-YYY1 22:30:00 and D2-M2-YYY2 04:30:00. You will always get a remainder of about twenty hours. This may become twenty-one hours or nineteen, and maybe eighteen hours, fifty-nine minutes thirty-six seconds. No matter. It is a large margin which will stay there and stay positive for the foreseeable future. Now you can truncate it with floor() in safety.

    作为替代,不要计算D1-M1-YYY1和d2 - m2 - yy2之间的差异。这些日期将被认为是D1-M1-YYY1 00:00和d2 - m2 - yyyyy2 00:00。相反,在d1 - m1 - yy1 22:30:00和d2 - m2 - yyyy2 04:30:00之间转换。你总能得到剩下的20个小时。这可能会变成21小时或19小时,也可能是18小时,59分36秒。不管。在可预见的未来,这将是一个巨大的利润空间,并将保持乐观。现在你可以在安全的地方把它截断。

The correct solution though is to

正确的解决方法是。

  • use a time library (Datetime, Carbon, whatever); don't roll your own

    使用时间库(Datetime, Carbon, whatever);不要使用你自己的

  • write comprehensive test cases using really evil date choices - across DST boundaries, across leap years, across leap seconds, and so on, as well as commonplace dates. Ideally (calls to datetime are fast!) generate four whole years' (and one day) worth of dates by assembling them from strings, sequentially, and ensure that the difference between the first day and the day being tested increases steadily by one. This will ensure that if anything changes in the low-level routines and leap seconds fixes try to wreak havoc, at least you will know.

    编写全面的测试用例,使用真正糟糕的日期选择——跨越DST边界,跨越闰年,跨越闰秒,等等,以及普通的日期。理想情况下(对datetime的调用是快速的!)通过连续地将它们从字符串中组合起来,生成4年(以及一天)的日期,并确保第一天和测试的第一天之间的差异会稳步增加。这将确保如果在低级常规和闰秒修复中发生了任何变化,那么至少您会知道。

  • run those tests regularly together with the rest of the test suite. They're a matter of milliseconds, and may save you literally hours of head scratching.

    定期与其他测试套件一起运行这些测试。它们只是几毫秒的事,而且可能会让你节省几个小时的挠头。


Whatever your solution, test it

The function funcdiff below implements one of the solutions (as it happens, the accepted one) in a real world scenario.

下面的函数在实际场景中实现了其中的一个解决方案(碰巧是被接受的)。

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

The result is,

其结果是,

This function failed 280 of its 14603 tests

Horror Story: the cost of "saving time"

This actually happened some months ago. An ingenious programmer decided to save several microseconds off a calculation that took about thirty seconds at most, by plugging in the infamous "(MidnightOfDateB-MidnightOfDateA)/86400" code in several places. It was so obvious an optimization that he did not even document it, and the optimization passed the integration tests and lurked in the code for several months, all unnoticed.

这实际上发生在几个月前。一个聪明的程序员决定节省几微秒的计算时间,这个计算花费了大约30秒的时间,并在几个地方插入了臭名昭著的“(MidnightOfDateB-MidnightOfDateA)/86400”代码。它是如此明显的优化,以至于他甚至没有记录它,而且优化通过了集成测试,并且在代码中潜伏了几个月,都没有被注意到。

This happened in a program that calculates the wages for several top-selling salesmen, the least of which has a frightful lot more clout than a whole humble five-people programmer team taken together. One day some months ago, for reasons that matter little, the bug struck -- and some of those guys got shortchanged one whole day of fat commissions. They were definitely not amused.

这发生在一个为几位最畅销的销售人员计算工资的程序中,其中最不重要的是要比一个由五人组成的普通程序员团队更有影响力。几个月前的某一天,由于一些无关紧要的原因,这只小虫子突然袭击了——其中的一些人在整整一天的时间里都被骗了。他们肯定不觉得有趣。

Infinitely worse, they lost the (already very little) faith they had in the program not being designed to surreptitiously shaft them, and pretended - and obtained - a complete, detailed code review with test cases ran and commented in layman's terms (plus a lot of red-carpet treatment in the following weeks).

无限更糟糕的是,他们失去了(已经很少)信仰他们的计划不是为了暗中轴,并假装和获得一个完整的、详细的代码评审与测试用例跑去从一个外行人的角度评论(加上很多红地毯待遇在接下来的几周)。

What can I say: on the plus side, we got rid of a lot of technical debt, and were able to rewrite and refactor several pieces of a spaghetti mess that hearkened back to a COBOL infestation in the swinging '90s. The program undoubtedly runs better now, and there's a lot more debugging information to quickly zero in when anything looks fishy. I estimate that just this last one thing will save perhaps one or two man-days per month for the foreseeable future.

我能说什么呢:从好的方面来说,我们摆脱了大量的技术债务,并且能够改写和重构几件意大利面的混乱,在90年代的摇摆中重新回到了COBOL的困扰。毫无疑问,这个程序现在运行得更好了,而且在任何看起来可疑的情况下,都有更多的调试信息可以快速地显示出来。我估计,在可预见的将来,这最后一件事可能会节省一到两个月的时间。

On the minus side, the whole brouhaha costed the company about €200,000 up front - plus face, plus undoubtedly some bargaining power (and, hence, yet more money).

-一侧,整个骚动估价公司大约€200000多面前,加上毫无疑问一些讨价还价的能力,因此,更多的钱。

The guy responsible for the "optimization" had changed job a year ago, before the disaster, but still there was talk to sue him for damages. And it didn't go well with the upper echelons that it was "the last guy's fault" - it looked like a set-up for us to come up clean of the matter, and in the end, we're still in the doghouse and one of the team is planning to quit.

一年前,在灾难发生之前,负责“优化”工作的那个人换了工作,但仍有传言说要起诉他,要求他赔偿损失。它和上层的人不太一样,那是“最后一个人的错”——这看起来像是我们要把事情弄清楚的准备,最后,我们仍然在狗窝里,其中一个团队正在计划退出。

Ninety-nine times out of one hundred, the "86400 hack" will work flawlessly. (For example in PHP, strtotime() will ignore DST and report that between the midnights of the last Saturday of October and that of the following Monday, exactly 2 * 24 * 60 * 60 seconds have passed, even if that is plainly not true... and two wrongs will happily make one right).

“86400黑客”将会完美地工作。(例如,在PHP中,strtotime()将忽略DST,并报告在10月的最后一个星期六的午夜和下一个星期一的午夜,正好2 * 24 * 60 * 60秒已经过去了,即使这显然不是真的……两个错误将使一个正确。

This, ladies and gentlemen, was one instance when it did not. As with air-bags and seat belts, you will perhaps never really need the complexity (and ease of use) of DateTime or Carbon. But the day when you might (or the day when you'll have to prove you thought about this) will come as a thief in the night. Be prepared.

女士们先生们,这是一个例外。与气囊和安全带一样,你可能永远也不需要DateTime或Carbon的复杂性(和易用性)。但是,当你有可能(或者你需要证明你的想法的那一天)的那天晚上,你会成为一个小偷。做好准备。

#6


16  

Easy to using date_diff

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

#7


15  

Object oriented style:

面向对象的风格:

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

Procedural style:

程序上的风格:

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

#8


9  

Well, the selected answer is not the most correct one because it will fail outside UTC. Depending on the timezone (list) there could be time adjustments creating days "without" 24 hours, and this will make the calculation (60*60*24) fail.

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

Here it is an example of it:

这里有一个例子:

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

So the correct solution will be using DateTime

所以正确的解决方案是使用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


7  

Used this :)

:使用)

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

Now it works

现在它的工作原理

#10


5  

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

#11


5  

I'm using Carbon in my composer projects for this and similar purposes.

我在我的作曲项目中使用碳来实现这个和类似的目的。

It'd be as easy as this:

就像这样简单:

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

#12


3  

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

and, if needed:

如果需要:

$datediff=abs($datediff);

#13


2  

If you have the times in seconds (I.E. unix time stamp) , then you can simply subtract the times and divide by 86400 (seconds per day)

如果您在几秒钟内拥有时间(即unix时间戳),那么您可以简单地减去时间,然后除以86400(秒/天)

#14


1  

function howManyDays($startDate,$endDate) {

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

return $res;
} 

#15


1  

If you want to echo all days between the start and end date, I came up with this :

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

$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


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

#17


0  

If you are using MySql

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

}

}

#18


0  

Here is my improved version which shows 1 Year(s) 2 Month(s) 25 day(s) if the 2nd parameter is passed.

这是我改进后的版本,如果第2个参数通过,则显示1年2个月(s) 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://*.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;
    }
}

#19


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

#20


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

used the above code very simple. Thanks.

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

#21


-1  

Try using Carbon

试着用碳

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

Also you can use

你也可以使用

\Carbon\Carbon::parse('')

to create an object of Carbon date using given timestamp string.

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

#22


-4  

This works!

这个工作!

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

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

#1


700  

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

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

#2


406  

If you're using PHP 5.3 >, this is by far the most accurate way of calculating the difference:

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

$date1 = new DateTime("2010-07-06");
$date2 = new DateTime("2010-07-09");

$diff = $date2->diff($date1)->format("%a");

#3


127  

From PHP Version 5.3 and up, new date/time functions have been added to get difference:

在PHP版本5.3和up中,添加了新的日期/时间函数来获得差异:

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

Result as below:

结果如下:

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
)

Hope it helps !

希望它可以帮助!

#4


122  

Convert your dates to unix timestamps, then substract one from the another. That will give you the difference in seconds, which you divide by 86400 (amount of seconds in a day) to give you an approximate amount of days in that range.

将您的日期转换为unix时间戳,然后从另一个中减去一个。这将给你带来不同的秒数,你可以用86400(一天内的秒数)来给你一个大致的天数。

If your dates are in format 25.1.2010, 01/25/2010 or 2010-01-25, you can use the strtotime function:

如果你的日期格式为25.1.2010,01/25/2010或2010-01-25,你可以使用strtotime函数:

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

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

Using ceil rounds the amount of days up to the next full day. Use floor instead if you want to get the amount of full days between those two dates.

使用ceil可以将几天的时间延长到下一个全天。如果你想在这两个日期之间获得足够的天数,可以使用地板。

If your dates are already in unix timestamp format, you can skip the converting and just do the $days_between part. For more exotic date formats, you might have to do some custom parsing to get it right.

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

#5


37  

TL;DR do not use UNIX timestamps. Do not use time(). If you do, be prepared should its 98.0825% reliability fail you. Use DateTime (or Carbon).

The correct answer is the one given by Saksham Gupta (other answers are also correct):

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

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

Or procedurally as a one-liner:

或者从程序上说,

/**
 * 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');
}

If you really must use UNIX timestamps, set the time zone to GMT to avoid most of the pitfalls detailed below.

如果您确实必须使用UNIX时间戳,请将时区设置为GMT,以避免下面详细介绍的大多数陷阱。


Long answer

Most of the answers using UNIX timestamps make two assumptions that, put together, can lead to scenarios with wrong results and subtle bugs that may be difficult to track, and arise even days, weeks or months after a successful deployment.

使用UNIX时间戳的大多数答案都有两个假设,它们组合在一起,可能导致错误的结果和难以跟踪的微妙错误,甚至在成功部署之后的几天、几周或几个月就会出现。

First mistake is not considering that when asked, "How many days passed since yesterday?", a computer might truthfully answer zero if between the present and the instant indicated by "yesterday" less than one whole day has passed.

第一个错误是,当被问到:“从昨天开始有多少天了?”如果在“昨天”和“昨天”之间的时间间隔不到一天,计算机可能会如实回答“0”。

Usually when converting a "day" to a UNIX timestamp, what is obtained is the timestamp for the midnight of that particular day.

通常,在将“day”转换为UNIX时间戳时,所得到的是该特定日期午夜的时间戳。

So between the midnights of October 1st and October 15th, fifteen days have elapsed. But between 13:00 of October 1st and 14:55 of October 15th, fifteen days minus 5 minutes have elapsed, and most solutions using floor() or doing implicit integer conversion will report one day less than expected.

所以在10月1日和10月15日的午夜之间,已经过去了15天。但是在10月1日13点到10月15日的14:55之间,15天减去5分钟已经过去了,大多数使用floor()或进行隐式整数转换的解决方案将比预期的少一天报告。

So, "how many days ago was Y-m-d H:i:s"? will yield the wrong answer.

那么,“多少天以前是Y-m-d H: s”?会产生错误的答案。

The second mistake is equating one day to 86400 seconds. This is almost always true - it happens often enough to overlook the times it doesn't. But the distance in seconds between two consecutive midnights is surely not 86400 at least twice a year when daylight saving time comes into play. Comparing two dates across a DST boundary will again yield the wrong answer.

第二个错误是将一天等同于86400秒。这几乎总是正确的——它经常发生,以至于忽略了它所没有的时间。但是,在两个连续的午夜之间的间隔时间肯定不是86400,至少是在夏令时开始时的两倍。将两个日期在DST边界上进行比较将再次产生错误的答案。

So even if you use the "hack" of forcing all date timestamps to a fixed hour, say midnight (this is also done implicitly by various languages and frameworks when you only specify day-month-year and not also hour-minute-second), the widely used formula

因此,即使你使用“hack”将所有日期时间戳强制到一个固定的时间,比如午夜(也可以通过各种语言和框架隐式地完成,当你只指定日- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -。

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

or

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

will return, say, 17 when DATE1 and DATE2 are in the same DST segment of the year; but it may return 17.042, and worse still, 16.958. The use of floor() or any implicit truncation to integer will then convert what should have been a 17 to a 16. In other circumstances, expressions like "$days > 17" will return true for 17.042 even if this indicates that the elapsed day count is 18.

当DATE1和DATE2在一年中的DST段时,将返回17;但它可能会返回17.042,更糟糕的是,16.958。使用floor()或任何隐式截断的整数将会转换为17到16的值。在其他情况下,像“$days > 17”这样的表达式将返回true,即使这表示经过的天数是18。

And things grow even uglier since such code is not portable across platforms, because some of them may apply leap seconds and some might not. On those platforms that do, the difference between two dates will not be 86400 but 86401, or maybe 86399. So code that worked in May and actually passed all tests will break next June when 12.99999 days are considered 12 days instead of 13. Two dates that worked in 2015 will not work in 2017 -- the same dates, and neither year is a leap year. But between 2018-03-01 and 2017-03-01, on those platforms that care, 366 days will have passed instead of 365, making 2017 a leap year.

而且,由于这些代码不能移植到平台上,因此事情变得更加糟糕,因为其中一些代码可能会应用闰秒,而有些则可能不会。在这些平台上,两个日期的区别不是86400,而是86401,或者可能是86399。因此,在5月份工作的代码实际上通过了所有测试,在明年6月,12.99999天被认为是12天,而不是13天。在2015年工作的两个日期将不会在2017年完成——同样的日期,而不是闰年。但在2013 -03-01和2017-03-01之间,在那些关心的平台上,366天将取代365天,使2017年成为闰年。

So if you really want to use UNIX timestamps:

所以如果你真的想使用UNIX时间戳:

  • use round() function wisely, not floor().

    明智地使用round()函数,而不是floor()。

  • as an alternative, do not calculate differences between D1-M1-YYY1 and D2-M2-YYY2. Those dates will be really considered as D1-M1-YYY1 00:00:00 and D2-M2-YYY2 00:00:00. Rather, convert between D1-M1-YYY1 22:30:00 and D2-M2-YYY2 04:30:00. You will always get a remainder of about twenty hours. This may become twenty-one hours or nineteen, and maybe eighteen hours, fifty-nine minutes thirty-six seconds. No matter. It is a large margin which will stay there and stay positive for the foreseeable future. Now you can truncate it with floor() in safety.

    作为替代,不要计算D1-M1-YYY1和d2 - m2 - yy2之间的差异。这些日期将被认为是D1-M1-YYY1 00:00和d2 - m2 - yyyyy2 00:00。相反,在d1 - m1 - yy1 22:30:00和d2 - m2 - yyyy2 04:30:00之间转换。你总能得到剩下的20个小时。这可能会变成21小时或19小时,也可能是18小时,59分36秒。不管。在可预见的未来,这将是一个巨大的利润空间,并将保持乐观。现在你可以在安全的地方把它截断。

The correct solution though is to

正确的解决方法是。

  • use a time library (Datetime, Carbon, whatever); don't roll your own

    使用时间库(Datetime, Carbon, whatever);不要使用你自己的

  • write comprehensive test cases using really evil date choices - across DST boundaries, across leap years, across leap seconds, and so on, as well as commonplace dates. Ideally (calls to datetime are fast!) generate four whole years' (and one day) worth of dates by assembling them from strings, sequentially, and ensure that the difference between the first day and the day being tested increases steadily by one. This will ensure that if anything changes in the low-level routines and leap seconds fixes try to wreak havoc, at least you will know.

    编写全面的测试用例,使用真正糟糕的日期选择——跨越DST边界,跨越闰年,跨越闰秒,等等,以及普通的日期。理想情况下(对datetime的调用是快速的!)通过连续地将它们从字符串中组合起来,生成4年(以及一天)的日期,并确保第一天和测试的第一天之间的差异会稳步增加。这将确保如果在低级常规和闰秒修复中发生了任何变化,那么至少您会知道。

  • run those tests regularly together with the rest of the test suite. They're a matter of milliseconds, and may save you literally hours of head scratching.

    定期与其他测试套件一起运行这些测试。它们只是几毫秒的事,而且可能会让你节省几个小时的挠头。


Whatever your solution, test it

The function funcdiff below implements one of the solutions (as it happens, the accepted one) in a real world scenario.

下面的函数在实际场景中实现了其中的一个解决方案(碰巧是被接受的)。

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

The result is,

其结果是,

This function failed 280 of its 14603 tests

Horror Story: the cost of "saving time"

This actually happened some months ago. An ingenious programmer decided to save several microseconds off a calculation that took about thirty seconds at most, by plugging in the infamous "(MidnightOfDateB-MidnightOfDateA)/86400" code in several places. It was so obvious an optimization that he did not even document it, and the optimization passed the integration tests and lurked in the code for several months, all unnoticed.

这实际上发生在几个月前。一个聪明的程序员决定节省几微秒的计算时间,这个计算花费了大约30秒的时间,并在几个地方插入了臭名昭著的“(MidnightOfDateB-MidnightOfDateA)/86400”代码。它是如此明显的优化,以至于他甚至没有记录它,而且优化通过了集成测试,并且在代码中潜伏了几个月,都没有被注意到。

This happened in a program that calculates the wages for several top-selling salesmen, the least of which has a frightful lot more clout than a whole humble five-people programmer team taken together. One day some months ago, for reasons that matter little, the bug struck -- and some of those guys got shortchanged one whole day of fat commissions. They were definitely not amused.

这发生在一个为几位最畅销的销售人员计算工资的程序中,其中最不重要的是要比一个由五人组成的普通程序员团队更有影响力。几个月前的某一天,由于一些无关紧要的原因,这只小虫子突然袭击了——其中的一些人在整整一天的时间里都被骗了。他们肯定不觉得有趣。

Infinitely worse, they lost the (already very little) faith they had in the program not being designed to surreptitiously shaft them, and pretended - and obtained - a complete, detailed code review with test cases ran and commented in layman's terms (plus a lot of red-carpet treatment in the following weeks).

无限更糟糕的是,他们失去了(已经很少)信仰他们的计划不是为了暗中轴,并假装和获得一个完整的、详细的代码评审与测试用例跑去从一个外行人的角度评论(加上很多红地毯待遇在接下来的几周)。

What can I say: on the plus side, we got rid of a lot of technical debt, and were able to rewrite and refactor several pieces of a spaghetti mess that hearkened back to a COBOL infestation in the swinging '90s. The program undoubtedly runs better now, and there's a lot more debugging information to quickly zero in when anything looks fishy. I estimate that just this last one thing will save perhaps one or two man-days per month for the foreseeable future.

我能说什么呢:从好的方面来说,我们摆脱了大量的技术债务,并且能够改写和重构几件意大利面的混乱,在90年代的摇摆中重新回到了COBOL的困扰。毫无疑问,这个程序现在运行得更好了,而且在任何看起来可疑的情况下,都有更多的调试信息可以快速地显示出来。我估计,在可预见的将来,这最后一件事可能会节省一到两个月的时间。

On the minus side, the whole brouhaha costed the company about €200,000 up front - plus face, plus undoubtedly some bargaining power (and, hence, yet more money).

-一侧,整个骚动估价公司大约€200000多面前,加上毫无疑问一些讨价还价的能力,因此,更多的钱。

The guy responsible for the "optimization" had changed job a year ago, before the disaster, but still there was talk to sue him for damages. And it didn't go well with the upper echelons that it was "the last guy's fault" - it looked like a set-up for us to come up clean of the matter, and in the end, we're still in the doghouse and one of the team is planning to quit.

一年前,在灾难发生之前,负责“优化”工作的那个人换了工作,但仍有传言说要起诉他,要求他赔偿损失。它和上层的人不太一样,那是“最后一个人的错”——这看起来像是我们要把事情弄清楚的准备,最后,我们仍然在狗窝里,其中一个团队正在计划退出。

Ninety-nine times out of one hundred, the "86400 hack" will work flawlessly. (For example in PHP, strtotime() will ignore DST and report that between the midnights of the last Saturday of October and that of the following Monday, exactly 2 * 24 * 60 * 60 seconds have passed, even if that is plainly not true... and two wrongs will happily make one right).

“86400黑客”将会完美地工作。(例如,在PHP中,strtotime()将忽略DST,并报告在10月的最后一个星期六的午夜和下一个星期一的午夜,正好2 * 24 * 60 * 60秒已经过去了,即使这显然不是真的……两个错误将使一个正确。

This, ladies and gentlemen, was one instance when it did not. As with air-bags and seat belts, you will perhaps never really need the complexity (and ease of use) of DateTime or Carbon. But the day when you might (or the day when you'll have to prove you thought about this) will come as a thief in the night. Be prepared.

女士们先生们,这是一个例外。与气囊和安全带一样,你可能永远也不需要DateTime或Carbon的复杂性(和易用性)。但是,当你有可能(或者你需要证明你的想法的那一天)的那天晚上,你会成为一个小偷。做好准备。

#6


16  

Easy to using date_diff

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

#7


15  

Object oriented style:

面向对象的风格:

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

Procedural style:

程序上的风格:

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

#8


9  

Well, the selected answer is not the most correct one because it will fail outside UTC. Depending on the timezone (list) there could be time adjustments creating days "without" 24 hours, and this will make the calculation (60*60*24) fail.

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

Here it is an example of it:

这里有一个例子:

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

So the correct solution will be using DateTime

所以正确的解决方案是使用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


7  

Used this :)

:使用)

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

Now it works

现在它的工作原理

#10


5  

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

#11


5  

I'm using Carbon in my composer projects for this and similar purposes.

我在我的作曲项目中使用碳来实现这个和类似的目的。

It'd be as easy as this:

就像这样简单:

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

#12


3  

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

and, if needed:

如果需要:

$datediff=abs($datediff);

#13


2  

If you have the times in seconds (I.E. unix time stamp) , then you can simply subtract the times and divide by 86400 (seconds per day)

如果您在几秒钟内拥有时间(即unix时间戳),那么您可以简单地减去时间,然后除以86400(秒/天)

#14


1  

function howManyDays($startDate,$endDate) {

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

return $res;
} 

#15


1  

If you want to echo all days between the start and end date, I came up with this :

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

$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


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

#17


0  

If you are using MySql

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

}

}

#18


0  

Here is my improved version which shows 1 Year(s) 2 Month(s) 25 day(s) if the 2nd parameter is passed.

这是我改进后的版本,如果第2个参数通过,则显示1年2个月(s) 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://*.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;
    }
}

#19


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

#20


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

used the above code very simple. Thanks.

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

#21


-1  

Try using Carbon

试着用碳

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

Also you can use

你也可以使用

\Carbon\Carbon::parse('')

to create an object of Carbon date using given timestamp string.

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

#22


-4  

This works!

这个工作!

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

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