2013-08-13 3 views
2

Пожалуйста, несите меня, пытаясь объяснить мое затруднительное положение. Мне нужно как-то получить разницу между двумя датами, изменив функцию, которую я должен добавить месяцами и годами?PHP Дата разницы с разницей

Задача Функция добавления даты, предоставленная с помощью PHP> = 5.3, не добавляет даты в соответствии с требованиями. Пример: +3 месяцев на 30Nov = 2Mar

Solution Я использую функцию ниже (код реф 2) для получения результатов, которые мне нужны. Пример: +3 месяцев до 30Nov = 28Feb

Однако при использовании ниже (код REF 1) для вычисления разницы он делает это на основе функции сложения обеспечивают PHP> = 5.3 в том, что я получаю 2 вместо разница в 3 месяца между 30Nov и 28Feb.

Если кто-нибудь может помочь придумать точную дату diff на основе кода ref 2 логики I, и я уверен, что другие в одной лодке будут очень благодарны.

< < КОД 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 
?> 

< < КОД 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 
?> 

РЕШЕНИЕ НАЙДЕНО

Изменяя путь мы используем оригинальную функцию мы вместо этого выясните количество лет и месяцев по желанию, ma благодаря всем полезным предложениям. Причина для 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 
} 
?> 
+1

Не могли бы вы объяснить, что именно вы пытаетесь достичь с помощью функции addMonths() в коде ref 2? – ciruvan

+0

Я изменил код ref 2, чтобы показать пример добавления от 3 месяцев до 30Nov, а для результата - 2001-02-28. – TSUK

+0

Итак, вы просите нас вывести рассуждения из всего кода из вашего кода? Почему бы не объяснить простыми словами, с несколькими примерами, как вы хотите, чтобы ваш алгоритм работал? – ciruvan

ответ

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); 
+0

Возможно, мне придется использовать этот метод, поскольку он технически дает правильные результаты, основанные на двух указанных датах. Однако это может быть неверно в другие даты. Я просто пытаюсь выяснить, возможно ли то, что я пытаюсь достичь (без функции, зная, как дата была изменена в первую очередь). – TSUK

+0

Если я правильно понял ваш вопрос, он должен дать правильный результат в любых используемых датах. –

2

Путь решения этой проблемы является расширить DateTime и overide надстройку() и к югу() методы вести себя как вы хотите. Это, в конце концов, одно из преимуществ ООП.

Способ получения желаемого поведения - установить день месяца на 1-й, прежде чем делать вызов add() или sub(), а затем восстанавливать исходный или максимально возможный день после этого.

Моя первая попытка ниже, не тщательно протестированы, но с добавлением 1 месяц до 31-го января дал 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); 
    } 
} 

Here is a working example using your exampe dates

Here is an example using the diff() method как вы может видеть, что это дает разницу в 3 месяца. Вы также можете видеть, что добавление итогового DateInterval к ​​исходной дате приводит к второй дате.

Метод sub() может потребовать немного больше мысли, но у меня нет времени только сейчас.Я посмотрю более внимательно, если через несколько минут я получу несколько запасных минут.

+0

thanks vascowhite - я буду использовать этот новый метод, однако мне действительно нужно использовать функцию latiff, которая дает результат так же, как и те, которые используются для вашего класса MyDateTime. Это меня действительно сбивает с толку, и теперь я начинаю думать, что это даже невозможно. – TSUK

+0

См. Мое редактирование для переопределения 'DateTime :: diff()'. Я думаю, что это должно сработать, но не может проверить его полностью сейчас. – vascowhite

Смежные вопросы