PHP日期差异有所不同 [英] PHP Date diff with a difference

查看:102
本文介绍了PHP日期差异有所不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请耐心等待我解释我的困境。我需要以某种方式获得两个日期之间的差异,通过换一个功能,我必须添加几个月和几年?



问题
PHP> = 5.3提供的date add函数不按照我的要求添加日期。
示例:+3个月至30Nov = 2Mar



解决方案
我使用功能如下(代码参考2),以产生我需要的结果。
示例:+3个月至30Nov = 28Feb



然而,当使用下面的(代码ref 1)计算差异时基于加法函数提供PHP> = 5.3,我得到2而不是30Nov和28Feb之间的3个月的差异。



如果有人可以帮助想出基于代码ref 2逻辑I的准确日期差异,我相信同一条船中的其他人将非常感谢。



<< CODE REF 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
?>

<< CODE REF 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->格式('Y-m-d'); // 2001-02-28
?>

解决方案



通过改变我们使用原始功能的方式,我们会根据需要找出年数和月份数,非常感谢所有有用的建议。 y = 1和m = 4的原因是因为一年从一开始,一个月从一个开始,否则如果从零开始,它将是原来要求的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
}
?>


解决方案

解决方法是延长DateTime并覆盖add()和sub()方法按照你想要的方式进行操作。这毕竟是OOP的优点之一。



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



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

  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()方法可能需要更多思考,但我不会刚才有时间。如果几分钟后我会休息一下,我会更彻底地看看。


Please bear with me as I try to explain my predicament. I need to somehow get the difference between two dates by reversing a function I have to add months and years?

Problem The date add function provided with PHP >= 5.3 does not add dates in the manner I require. Example: +3 Months to 30Nov = 2Mar

Solution I use the function below (code ref 2) to produce the results I need. Example: +3 Months to 30Nov = 28Feb

However when using the below (code ref 1) to calculate the difference it does so based on the addition function provide with PHP >= 5.3 in that I get 2 instead of 3 months difference between 30Nov and 28Feb.

If anyone could help come up with an accurate date diff based on the code ref 2 logic I, and I'm sure others in the same boat would be very grateful.

<< CODE REF 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
?>

<< CODE REF 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
?>

SOLUTION FOUND

By changing the way we use the original function we instead find out the number of years and months as desired, many thanks to all the helpful suggestions. The reason for y=1 and m=4 is because the year starts at one and the month starts at one, otherwise it would be 0 and 3 as originally requested if starting at zero.

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

解决方案

The way to approach this is to extend DateTime and overide the add() and sub() methods to behave as you want them to. That, after all is one of the advantages of OOP.

The way to get your desired behaviours is to set the day of the month to the 1st before doing calling add() or sub() and then restoring the original or highest possible day afterwards.

My first attempt is below, not thoroughly tested, but adding 1 month to 31st Jan gave 28th Feb, which, I believe is your desired behaviour:-

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

Here is a working example using your exampe dates

Here is an example using the diff() method as you can see it gives a 3 month difference. You can also see that adding the resulting DateInterval to the original date results in the second date.

The sub() method may require a bit more thought, but I don't have time just now. I'll take a more thorough look if I get a few spare minutes later.

这篇关于PHP日期差异有所不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆