【问题标题】:Calculate the number of months between two dates in PHP?计算PHP中两个日期之间的月数?
【发布时间】:2012-11-16 12:47:47
【问题描述】:

不使用 PHP 5.3 的 date_diff 函数(我使用的是 PHP 5.2.17),有没有一种简单而准确的方法来做到这一点?我正在考虑类似下面的代码,但我不知道如何计算闰年:

$days = ceil(abs( strtotime('2000-01-25') - strtotime('2010-02-20') ) / 86400);
$months = ???;

我正在计算一个人的月龄。

【问题讨论】:

  • 这是否也排除了DateTime 类?
  • 有什么理由不喜欢 php.net 上的解决方案? php.net/manual/en/datetime.diff.php#107434这个
  • 月数到底是什么意思?同年 10 月 5 日和 11 月 3 日之间的月份相差多少?那么 10 月 31 日和 11 月 1 日呢?
  • 计算年数,乘以 12,结束月份减去开始月份,然后对天数做同样的操作。 -edit- 或者按照 deceze 的建议做 ;)
  • 谢谢大家,我现在更新了应该回答您的问题的问题。 @NappingRabbit,它非常长!

标签: php date


【解决方案1】:
$date1 = '2000-01-25';
$date2 = '2010-02-20';

$ts1 = strtotime($date1);
$ts2 = strtotime($date2);

$year1 = date('Y', $ts1);
$year2 = date('Y', $ts2);

$month1 = date('m', $ts1);
$month2 = date('m', $ts2);

$diff = (($year2 - $year1) * 12) + ($month2 - $month1);

您可能还想在某处包含天数,具体取决于您的意思是 整个 个月与否。不过希望你能明白。

【讨论】:

  • 非常感谢@deceze,看起来不错!正如您所建议的,它需要考虑天数才能准确地反映一个人的年龄。你能建议怎么做吗?
  • 如果有帮助的话,我已经为我的解决方案增加了几天时间。
  • 实际上这种方法比其他方法效果更好。例如,date_diff()2009-09-012010-05-01 之间产生“7 个月零30 天”的差异,而此解决方案总是产生“8 个月”。
  • 优秀的工作伙伴
  • 你拯救了我的一天,非常感谢 :)
【解决方案2】:

这是我在课堂上编写的一个简单方法,用于计算两个给定日期所涉及的月数:

public function nb_mois($date1, $date2)
{
    $begin = new DateTime( $date1 );
    $end = new DateTime( $date2 );
    $end = $end->modify( '+1 month' );

    $interval = DateInterval::createFromDateString('1 month');

    $period = new DatePeriod($begin, $interval, $end);
    $counter = 0;
    foreach($period as $dt) {
        $counter++;
    }

    return $counter;
}

【讨论】:

  • 感谢这帮了大忙 :)
  • 您可以简单地使用iterator_count($period),而不是循环遍历该期间
  • 我真的很喜欢这个解决方案,尤其是@Koen。的替换循环。
  • 我把它改成了 $end = $end->modify( '+1 day' );在我的代码中,效果很好
【解决方案3】:

这是我的解决方案。它会检查日期的年份和月份并找出差异。

 $date1 = '2000-01-25';
 $date2 = '2010-02-20';
 $d1=new DateTime($date2); 
 $d2=new DateTime($date1);                                  
 $Months = $d2->diff($d1); 
 $howeverManyMonths = (($Months->y) * 12) + ($Months->m);

【讨论】:

  • 我认为最干净的解决方案但设置时区参数 $d1=new DateTime($date2, new DateTimeZone('Europe/Paris') )
  • 完美的解决方案,清洁剂
【解决方案4】:

像这样:

$date1 = strtotime('2000-01-25');
$date2 = strtotime('2010-02-20');
$months = 0;

while (($date1 = strtotime('+1 MONTH', $date1)) <= $date2)
    $months++;

echo $months;

如果你想包含天数,那么使用这个:

$date1 = strtotime('2000-01-25');
$date2 = strtotime('2010-02-20');

$months = 0;

while (strtotime('+1 MONTH', $date1) < $date2) {
    $months++;
    $date1 = strtotime('+1 MONTH', $date1);
}

echo $months, ' month, ', ($date2 - $date1) / (60*60*24), ' days'; // 120 month, 26 days

【讨论】:

  • 这会告诉你在 2012-01-01 和 2012-02-01 之间有两个月。即使您将 Feb-2 时间跨度产生两个月,这可能不是最佳解决方案。
  • 使用您指定的日期我得到 1 返回,因为它会在检查 $date1 是否小于并添加一个月之前更新它。
  • 啊太棒了!效果很好!谢谢亚当
  • 所有使用这个的人,请注意 while 语句,它的迭代有一些限制值。我并不是说代码是否错误,只是在使用迭代语句时要注意一点安全。
【解决方案5】:

这就是我最终解决它的方法。我知道我来晚了,但我希望这可以为某人节省大量时间和代码行数。
我使用 DateInterval::format 以年、月和日的形式显示人类可读的倒计时时钟。 检查https://www.php.net/manual/en/dateinterval.format.php 以查看格式表以查看有关如何修改返回值的选项。应该给你你正在寻找的东西。

$origin = new DateTime('2020-10-01');
$target = new DateTime('2020-12-25');
$interval = $origin->diff($target);
echo $interval->format('%y years, %m month, %d days until Christmas.');

输出:0 年 2 个月 24 天

【讨论】:

    【解决方案6】:

    这是我的解决方案。它只检查日期的年份和月份。所以,如果一个日期是 31.10.15 而另一个是 02.11.15 它返回 1 个月。

    function get_interval_in_month($from, $to) {
        $month_in_year = 12;
        $date_from = getdate(strtotime($from));
        $date_to = getdate(strtotime($to));
        return ($date_to['year'] - $date_from['year']) * $month_in_year -
            ($month_in_year - $date_to['mon']) +
            ($month_in_year - $date_from['mon']);
    }
    

    【讨论】:

      【解决方案7】:

      我解决问题的功能

      function diffMonth($from, $to) {
      
              $fromYear = date("Y", strtotime($from));
              $fromMonth = date("m", strtotime($from));
              $toYear = date("Y", strtotime($to));
              $toMonth = date("m", strtotime($to));
              if ($fromYear == $toYear) {
                  return ($toMonth-$fromMonth)+1;
              } else {
                  return (12-$fromMonth)+1+$toMonth;
              }
      
          }
      

      【讨论】:

        【解决方案8】:

        我最近需要计算从产前到 5 岁(60 个月以上)的月龄。

        以上答案都不适合我。 我尝试的第一个,基本上是 deceze 答案的 1 班轮

        $bdate = strtotime('2011-11-04'); 
        $edate = strtotime('2011-12-03');
        $age = ((date('Y',$edate) - date('Y',$bdate)) * 12) + (date('m',$edate) - date('m',$bdate));
        . . .
        

        设置日期失败,显然答案应该是 0,因为尚未达到月标记 (2011-12-04),但是代码返回 1。

        我尝试的第二种方法,使用亚当的代码

        $bdate = strtotime('2011-01-03'); 
        $edate = strtotime('2011-02-03');
        $age = 0;
        
        while (strtotime('+1 MONTH', $bdate) < $edate) {
            $age++;
            $bdate = strtotime('+1 MONTH', $bdate);
        }
        . . .
        

        这失败了,说 0 个月,应该是 1。

        对我有用的是对这段代码进行了一点扩展。我使用的是以下内容:

        $bdate = strtotime('2011-11-04');
        $edate = strtotime('2012-01-04');
        $age = 0;
        
        if($edate < $bdate) {
            //prenatal
            $age = -1;
        } else {
            //born, count months.
            while($bdate < $edate) {
                $age++;
                $bdate = strtotime('+1 MONTH', $bdate);
                if ($bdate > $edate) {
                    $age--;
                }
            }
        }
        

        【讨论】:

          【解决方案9】:

          我的解决方案是混合几个答案。我不想做一个循环,特别是当我在 $interval->diff 中有所有数据时,我只是做了数学计算,如果就我而言,月数可能是负数,所以这是我的方法。

              /**
               * Function will give you the difference months between two dates
               *
               * @param string $start_date
               * @param string $end_date
               * @return int|null
               */
              public function get_months_between_dates(string $start_date, string $end_date): ?int
              {
                  $startDate = $start_date instanceof Datetime ? $start_date : new DateTime($start_date);
                  $endDate = $end_date instanceof Datetime ? $end_date : new DateTime($end_date);
                  $interval = $startDate->diff($endDate);
                  $months = ($interval->y * 12) + $interval->m;
                  
                 return $startDate > $endDate ? -$months : $months;
                  
              }
          

          【讨论】:

            【解决方案10】:

            跟进@deceze 的回答(我对他的回答投了赞成票)。即使第一个日期的没有到达第二个日期的日期,月份仍然会被计算在内。

            这是我关于包括这一天的简单解决方案:

            $ts1=strtotime($date1);
            $ts2=strtotime($date2);
            
            $year1 = date('Y', $ts1);
            $year2 = date('Y', $ts2);
            
            $month1 = date('m', $ts1);
            $month2 = date('m', $ts2);
            
            $day1 = date('d', $ts1); /* I'VE ADDED THE DAY VARIABLE OF DATE1 AND DATE2 */
            $day2 = date('d', $ts2);
            
            $diff = (($year2 - $year1) * 12) + ($month2 - $month1);
            
            /* IF THE DAY2 IS LESS THAN DAY1, IT WILL LESSEN THE $diff VALUE BY ONE */
            
            if($day2<$day1){ $diff=$diff-1; }
            

            逻辑是,如果第二个日期的日期小于第一个日期的日期,则将$diff变量的值减1。

            【讨论】:

              【解决方案11】:

              这个怎么样:

              $d1 = new DateTime("2009-09-01");
              $d2 = new DateTime("2010-09-01");
              $months = 0;
              
              $d1->add(new \DateInterval('P1M'));
              while ($d1 <= $d2){
                  $months ++;
                  $d1->add(new \DateInterval('P1M'));
              }
              
              print_r($months);
              

              【讨论】:

                【解决方案12】:
                $date1 = '2000-01-25';
                $date2 = '2010-02-20';
                
                $ts1 = strtotime($date1);
                $ts2 = strtotime($date2);
                
                $year1 = date('Y', $ts1);
                $year2 = date('Y', $ts2);
                
                $month1 = date('m', $ts1);
                $month2 = date('m', $ts2);
                
                $diff = (($year2 - $year1) * 12) + ($month2 - $month1);
                

                如果月份从一月切换到二月,上面的代码将返回 $diff = 1 但是,如果您只想在 30 天后考虑下个月,请在上面添加下面的代码行。

                $day1 = date('d', $ts1);
                $day2 = date('d', $ts2);
                
                if($day2 < $day1){ $diff = $diff - 1; }
                

                【讨论】:

                  【解决方案13】:

                  为了计算两个日期之间的日历月数(也被问到here),我通常最终会做这样的事情。我将这两个日期转换为“2020-05”和“1994-05”之类的字符串,然后从下面的函数中获取它们各自的结果,然后对这些结果进行减法运算。

                  /**
                   * Will return number of months. For 2020 April, that will be the result of (2020*12+4) = 24244
                   * 2020-12 = 24240 + 12 = 24252
                   * 2021-01 = 24252 + 01 = 24253
                   * @param string $year_month Should be "year-month", like "2020-04" etc.
                   */
                  static private function calculate_month_total($year_month)
                  {
                      $parts = explode('-', $year_month);
                      $year = (int)$parts[0];
                      $month = (int)$parts[1];
                      return $year * 12 + $month;
                  }
                  

                  【讨论】:

                    【解决方案14】:
                    function date_duration($date){
                        $date1 = new DateTime($date);
                        $date2 = new DateTime();
                        $interval = $date1->diff($date2);
                        if($interval->y > 0 and $interval->y < 2){
                            return $interval->y.' year ago';
                        }else if($interval->y > 1){
                            return $interval->y.' years ago';
                        }else if($interval->m > 0 and $interval->m < 2){
                            return $interval->m.' month ago';
                        }else if($interval->m > 1){
                            return $interval->y.' months ago';
                        }else if($interval->d > 1){
                            return $interval->d.' days ago';
                        }else{
                            if($interval->h > 0 and $interval->h < 2){
                                return $interval->h.' hour ago';
                            }else if($interval->h > 1){
                                return $interval->h.' hours ago';
                            }else{
                                if($interval->i > 0 and $interval->i < 2){
                                    return $interval->i.' minute ago';
                                }else if($interval->i > 1){
                                    return $interval->i.' minutes ago';
                                }else{
                                    return 'Just now';
                                }
                            }
                        }
                    }
                    

                    返回 11 个月前、2 年前、5 分钟前的日期区分样式

                    例子:

                    echo date_duration('2021-02-28 14:59:00.00');
                    

                    将根据您当前的月份返回“1 个月前”

                    【讨论】:

                      【解决方案15】:

                      我只是想分享我写的函数。 您可以通过输入相关的日期时间格式来修改它以获得月份和年份,以定义修饰符 aka modify("+1 something")。

                      /**
                       * @param DateTimeInterface $start a anything using the DateTime interface
                       * @param DateTimeInterface|null $end to calculate the difference to
                       * @param string $modifier for example: day or month or year.
                       * @return int the count of periods.
                       */
                      public static function elapsedPeriods(
                                             DateTimeInterface $start, 
                                             DateTimeInterface $end = null, 
                                             string            $modifier = '1 month'
                      ): int
                      {
                      
                          // just an addition, in case you just want the periods up untill now
                          if ($end === null ) {
                              $end = new DateTime();
                          }
                      
                          // we clone the start, because we dont want to change the actual start
                          // (objects are passed by ref by default, so if you forget this you might 
                          // mess up your data)
                          $cloned_start = clone $start;
                      
                          // we create a period counter, starting at zero, because we want to count 
                          // periods, assuming the first try, makes one period. 
                          // (week, month, year, et cetera) 
                          $period_count = 0;
                          
                          // so while our $cloned_start is smaller to the $end (or now).
                          // we will increment the counter
                          while ($cloned_start < $end) {
                              // first off we increment the count, for the first iteration could end 
                              // the cycle
                              $period_count++;
                              // now we modify the cloned start
                              $cloned_start->modify(sprintf("+1 %s", $modifier));
                          }
                      
                          return $period_count; // return the count
                      }
                      

                      干杯

                      【讨论】:

                        猜你喜欢
                        • 2018-04-13
                        • 1970-01-01
                        • 2021-07-20
                        • 2019-06-07
                        • 1970-01-01
                        • 2010-12-04
                        • 2022-11-18
                        • 1970-01-01
                        相关资源
                        最近更新 更多