8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

查找两个日期之间的天数

Goran_Ilic_Ilke 2月前

247 0

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

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

帖子版权声明 1、本帖标题:查找两个日期之间的天数
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Goran_Ilic_Ilke在本站《datetime》版块原创发布, 转载请注明出处!
最新回复 (0)
  • $now = time(); // or your date as well
    $your_date = strtotime("2010-01-31");
    $datediff = $now - $your_date;
    
    echo round($datediff / (60 * 60 * 24));
    
  • 我认为返回负数天数可以提供相关信息。如果您希望未来日期返回正整数,则应使用 $your_date-$now。

  • 那闰秒呢?并不是所有的日子都有精确的 24*60*60 秒。此代码可能足以满足实际用途,但在某些极其罕见的边缘情况下并不精确。

  • 忘记闰秒(不,实际上也要考虑闰秒),但这不考虑夏令时的变化!每年它可能会超出这些界限一整天。您需要使用 DateTime 类。

  • @billynoah 抱歉,我再也没有回来更新我的评论。你必须小心夏令时区。如果你将夏令时的日期与没有夏令时的日期进行比较,例如返回 7 天,它返回 6.9 天。发言权返回 6 而不是 7。

  • strtotime() 不仅在 20 年后失效,而且现在也无法使用。OP 指定的是日期,而不是时间。日期可能很旧。这是一个更简单的答案:$NumberDays = gregoriantojd($EndM,$EndD,$EndY) - gregoriantojd($StartM,$StartD,$StartY);(包含范围)。与 Datetime 类不同,公历到儒略历在 v4 及以上版本中可用。有效范围是公元前 4714 年至公元 9999 年。请注意古怪的参数顺序(就像您需要 php 的警告一样)。

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

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

    如果您需要相对(有符号)的天数,请使用以下命令:

    $earlier = new DateTime("2010-07-06");
    $later = new DateTime("2010-07-09");
    
    $pos_diff = $earlier->diff($later)->format("%r%a"); //3
    $neg_diff = $later->diff($earlier)->format("%r%a"); //-3
    

    有关 php DateInterval 格式的更多信息可以在这里找到: https://www.php.net/manual/en/dateinterval.format.php

  • 请注意,由于我们讨论的是时间间隔而不是特定时间点,因此格式语法与 date() 和 strftime() 语法不同。时间间隔语法可在此处找到:php.net/manual/en/dateinterval.format.php

  • Eero 2月前 0 只看Ta
    引用 10

    或者在我的情况下,之间的天数是 $date2->diff($date1)->format(\'%a\') - 1

  • 请记住,如果您的日期中包含时间,则这将无法按预期工作。例如,如果您的间隔为 23:30 小时...并且它们位于不同的日期,则差值将为 0。

  • 如果您需要相对天数(当 $date1 早于 $date2 时为负数),则使用 $diff = $date2->diff($date1)->format(\'%r%a\'); 。

  • 引用 13

    该函数在 1980 年至 2020 年期间进行的 14603 次测试中,有 0 次失败。

  • Biju 2月前 0 只看Ta
    引用 14

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

    希望有帮助!

  • 是的,这似乎比接受的答案更好,在某些情况下,接受的答案不起作用。例如:$from='2014-03-01'; $to='2014-03-31';

  • 我同意,这很容易理解,而且效果很好!只是不要忘记使用 date_default_timezone_set() 函数,否则它会根据 UTC 时间给出奇怪的结果。

  • 在 1980 年至 2020 年期间进行的 14603 次测试中,此功能有 0 次失败。

  • 这并不总是正确的。尝试:$fromDate = \'2020-08-29\'; $toDate = \'2021-03-02\'; 返回 0 年,6 个月,4 天。但它应该是 6 个月,2 天

  • 引用 19

    TL;DR 不要 使用 UNIX 时间戳。 不要 Do not use 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)的答案都做出了两个假设,这两个假设结合在一起,可能会导致 错误的结果 细微错误 ,甚至在成功部署后的几天、几周或几个月后才会出现。这并不是说解决方案不起作用——它有效。今天。但它明天可能会停止工作。

    ”时,如果从现在到“昨天”所表示的时刻之间还不 一天 ,计算机可能会如实地回​​答

    通常,将“天”转换为 UNIX 时间戳时,获得的是 该特定天的 午夜

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

    因此,\'Ymd H:i:s 是多少天前\'?将得出 错误答案 .

    第二个错误是将一天等同于 86400 秒。这 几乎总是 正确的——这种情况经常发生,以至于忽略了不等的情况。但是,当夏令时开始发挥作用时,每年至少有两次连续午夜之间的秒数 肯定 不是 86400。跨 DST 边界比较两个日期将得出错误的答案。

    因此,即使你使用“黑客”将所有日期时间戳强制为固定小时,比如午夜(当你只指定日-月-年而不是时-分-秒时,各种语言和框架也会隐式地执行此操作;MySQL 等数据库中的 DATE 类型也是如此),广泛使用的公式

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

    或者

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

    例如,当 DATE1 和 DATE2 处于一年中的同一 DST 段时,将返回 17;但即使时:分:秒部分相同,参数也可能为 17.042,更糟糕的是,当它们处于不同的 DST 段并且时区支持 DST 时,参数可能为 16.958。使用 floor() 或任何隐式截断为整数会将本应为 17 的值转换为 16。在其他情况下,像 \'$days > 17\' 这样的表达式将返回 true 17.042,即使这看起来好像已过去的天数是 18。

    事情变得更加糟糕,因为这样的代码 不能 跨平台移植,因为 有些平台可能会应用闰秒,有些则不会 。在那些 支持 ,两个日期之间的差值不是 86400 而是 86401,或者可能是 86399。因此,5 月份运行正常且通过所有测试的代码将在明年 6 月失效,因为那时 12.99999 天被认为是 12 天而不是 13 天。2015 年运行正常的两个日期在 2017 年将无法运行 —— 日期 相同 ,而且都不是闰年。而在 2018-03-01 和 2017-03-01 之间,在那些关心闰年的平台上, 366 天而不是 365 天,这使得 2018 年成为闰年(但事实并非如此)。

    因此,如果您确实想使用 UNIX 时间戳:

    • 第15页

    • p16

    正确的 方案

    • p18

    • 第19页

    • p20


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

    函数 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";
    print " between {$yearFrom} and {$yearTo}.\n";
    

    结果是,

    This function failed 280 of its 14603 tests
    

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

    一切始于 2014 年末。一位聪明的程序员决定在最多需要三十秒的计算中节省几微秒,方法是在多个地方插入臭名昭著的 \'(MidnightOfDateB-MidnightOfDateA)/86400\' 代码。这是一项明显的优化,他甚至没有记录下来,而这项优化通过了集成测试,并以某种方式潜伏在代码中几个月,却无人注意。

    这件事发生在一个计算几位顶级销售员工资的程序中,其中最不重要的一位的影响力比整个五人程序员团队的影响力加起来还要大得多。2015 年 3 月 28 日,夏令时区启动,漏洞出现—— 其中一些 人被少付了一整天的巨额佣金。更糟糕的是,他们中的大多数人周日不上班,而且快到月底了,他们利用这一天来赶上他们的发票。他们肯定 不高兴

    更糟糕的是,他们失去了(已经很少了)对程序 设计 不是 获得了 ——一个完整、详细的代码审查,其中的测试用例以外行人能理解的语言进行运行和评论(加上接下来几周的大量红地毯待遇)。

    我能说什么呢:积极的一面是,我们摆脱了大量技术债务,并且能够重写和重构一些乱七八糟的东西,这些乱七八糟的东西让人回想起 90 年代 COBOL 泛滥的时期。毫无疑问,现在程序运行得更好了,当任何可疑的东西出现时,有更多的调试信息可以快速定位。我估计,在可预见的未来,仅这最后一件事就可以每月节省一到两个人的时间,因此灾难 会有 一线希望,甚至是一线希望。

    不利的一面是,整个风波让公司预先损失了大约 20 万欧元,另外还损失了面子,毫无疑问还损失了一些议价能力(因此,损失的钱也更多了)。

    负责“优化”的人早在 2014 年 12 月就换了工作,远在灾难发生之前,但仍有传言称要起诉他并要求赔偿。而高层对此并不满意,认为这是“上一个人的错”——这看起来像是一场阴谋,让我们把这件事说得一清二楚,最终,我们在那一年的剩余时间里一直处于困境之中,团队中的一名成员在那个夏天末辞职了。

    百分之九十九的情况下,“86400 hack”都能完美运行。(例如在 PHP 中, strtotime() 会忽略 DST,并报告在 10 月最后一个星期六的午夜和下周一的午夜之间恰好过去了 2 * 24 * 60 * 60 秒,即使这显然不是 真的 ……两个错误恰好可以凑成一个正确)。

    女士们先生们,这就是 一个 没有实现的例子。与安全气囊和安全带一样,您可能永远 不需要 DateTime 的复杂性(和易用性) Carbon 。但有一天,您 可能 (或您必须 证明 您考虑过这一点)的那一天会像夜里的贼一样到来(可能是十月某个星期天的凌晨 2 点)。做好准备。

  • 当我看到这些答案时,我以为我很愚蠢和疯狂,因为我总是使用 DateTime,但你让我明白使用 DateTime 是正确的方法。谢谢

返回
作者最近主题: