PHP日期差异有所不同 [英] PHP Date diff with a difference
问题描述
问题
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屋!