2

请耐心等待我试图解释我的困境。我需要通过反转我必须添加月份和年份的函数来以某种方式获得两个日期之间的差异?

问题 PHP >= 5.3 提供的日期添加功能没有按我要求的方式添加日期。 示例:+3 个月到 30Nov = 2Mar

解决方案 我使用下面的函数(代码参考 2)来产生我需要的结果。 示例:+3 个月至 11 月 30 日 = 2 月 28 日

但是,当使用下面的代码(代码参考 1)计算差异时,它是基于 PHP >= 5.3 提供的加法函数计算的,因为我在 11 月 30 日和 2 月 28 日之间得到 2 而不是 3 个月的差异。

如果有人可以根据代码 ref 2 逻辑 I 帮助提出准确的日期差异,我相信同一条船上的其他人会非常感激。

<< 代码参考 1 >>

<?php
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-02-28');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%m'); // 2

$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-03-02');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%m'); // 3
?>

<< 代码参考 2 >>

<?php       
$datetime = new DateTime('2000-11-30');
$y = 0;
$m = 3;
$d = 0;
if ($d>0){
    $datetime->add(new DateInterval('P'.$d.'D'));
}
if ($d<0){
    $datetime->sub(new DateInterval('P'.$d.'D'));
}
if ($y!=0){
    $init=clone $datetime;
       $modifier=$y.' years';
       $datetime->modify($modifier);
       while ($datetime->format('m')!=$init->format('m')){
        $datetime->modify('-1 day');
    }
}
if ($m!=0){
    $init=clone $datetime;
    $modifier=$m.' months';
    $back_modifier =-$m.' months';
    $datetime->modify($modifier);
    $back_to_init= clone $datetime;
    $back_to_init->modify($back_modifier);
    while ($init->format('m')!=$back_to_init->format('m')){
        $datetime->modify('-1 day');
        $back_to_init= clone $datetime;
        $back_to_init->modify($back_modifier);   
    }
}
echo $datetime->format('Y-m-d'); // 2001-02-28
?>

找到解决方案

通过改变我们使用原始函数的方式,我们可以根据需要找出年数和月数,非常感谢所有有用的建议。y=1 和 m=4 的原因是因为年从 1 开始,月份从 1 开始,否则如果从 0 开始,它将是最初要求的 0 和 3。

<?php
function date_yr_mth($date1='2000-11-30',$date2='2001-02-28'){
    $y1 = date("Y", strtotime($date1));
    $m1 = date("n", strtotime($date1));
    $d1 = date("j", strtotime($date1));
    $y2 = date("Y", strtotime($date2));
    $m2 = date("n", strtotime($date2));
    $d2 = date("j", strtotime($date2));
    $t2 = date("t", strtotime($date2));
    $cm_diff = $m2-$m1;
    $cy_diff = $y2-$y1;
    if ($d2>=$d1){
        $add_mth1 = 1;
    }else{
        $add_mth1 = 0;
    }
    $add_mth2 = 12*$cy_diff+$cm_diff;
    if ($d2==$t2 && $d2<$d1){
        $add_mth3 = 1;
    }else{
        $add_mth3 = 0;
    }
    $total_mths = $add_mth1+$add_mth2+$add_mth3;
    $arr = array();
    $arr['y'] = floor(($total_mths-1)/12)+1;
    $arr['m'] = $total_mths-($arr['y']-1)*12;
    print_r($arr);
    // [y] => 1
    // [m] => 4
}
?>
4

2 回答 2

2

解决此问题的方法是扩展 DateTime 并覆盖 add() 和 sub() 方法以按照您的意愿行事。这毕竟是 OOP 的优势之一。

获得所需行为的方法是在调用 add() 或 sub() 之前将一个月中的日期设置为 1 号,然后在之后恢复原始日期或可能的最高日期。

我的第一次尝试在下面,没有经过彻底测试,但是在 1 月 31 日加上 1 个月到了 2 月 28 日,我相信这是你想要的行为:-

class MyDateTime extends \DateTime
{
    public function add($interval)
    {
        $oldDay = (int)$this->format('d');
        $this->setDate((int)$this->format('Y'), (int)$this->format('m'), 1);
        parent::add($interval);
        $maxDay = (int)$this->format('t');
        if($oldDay > $maxDay){
            $this->setDate((int)$this->format('Y'), (int)$this->format('m'), $maxDay);
        } else {
            $this->setDate((int)$this->format('Y'), (int)$this->format('m'), $oldDay);
        }
        return $this;
    }

    public function sub($interval)
    {
        $oldDay = (int)$this->format('d');
        $this->setDate((int)$this->format('Y'), (int)$this->format('m'), 1);
        parent::sub($interval);
        $maxDay = (int)$this->format('t');
        if($oldDay > $maxDay){
            $this->setDate((int)$this->format('Y'), (int)$this->format('m'), $maxDay);
        } else {
            $this->setDate((int)$this->format('Y'), (int)$this->format('m'), $oldDay);
        }
        return $this;
    }

    public function diff($dateTime2, $absolute = false)
    {
        if((int)$this->format('t') > (int)$dateTime2->format('t')){
            $this->setDate((int)$this->format('Y'), (int)$this->format('m'), (int)$dateTime2->format('t'));
        }
        if((int)$this->format('t') < (int)$dateTime2->format('t')){
            $dateTime2->setDate((int)$dateTime2->format('Y'), (int)$dateTime2->format('m'), (int)$this->format('t'));
        }
        return parent::diff($dateTime2, $absolute);
    }
}

这是一个使用您的考试日期的工作示例

这是一个使用 diff() 方法的示例,您可以看到它给出了 3 个月的差异。您还可以看到将生成的 DateInterval 添加到原始日期会产生第二个日期。

sub() 方法可能需要更多的思考,但我现在没有时间。如果我有几分钟的空闲时间,我会更彻底地看一下。

于 2013-08-13T09:26:00.630 回答
1

这样,您就可以在不考虑日期的情况下获得月份之间的绝对差异。

 <?php
function getMonthDiff($firstMonth, $secondMonth)
{
    $firstMonth  = $firstMonth->format("Y") * 12 + $firstMonth->format("m");
    $secondMonth = $secondMonth->format("Y") * 12 + $secondMonth->format("m");

    return abs($firstMonth - $secondMonth);
}


$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-02-28');
echo getMonthDiff($datetime1, $datetime2);
echo "<br />";
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-03-02');
echo getMonthDiff($datetime1, $datetime2);
于 2013-08-13T09:14:27.073 回答