Autor Zpráva
Marecek
Profil *
Dobrý deň,

potreboval by som zistiť rozdiel medzi dvoma dátumami, vytvoril som si na to funkciu..
  function pocetDni($from, $to) 
  {
      $first_date = strtotime($from);
      $second_date = strtotime($to);
      $offset = $second_date - $first_date; 
      return floor($offset/60/60/24);
  }  

Funkcia je síce fajn ale stále mám 2 problémy..
1., ak dáte napr. pocetDni("2013-03-30", "2013-04-30") vráti 30 čo v určitej situácií je ok ale ja reálne chcem aby zahrnul aj prvý deň (30.03-2013) a posledný deň (30.04.2013) teda správne by to malo byť 32. Chcem to vyriešiť nejako inteligentne, teda nie natvrdo +2.. príde mi to ako "nepekné" riešenie..

2. Druhá vec sú dátumy ktoré trvajú dlhšie obdobie, napr. pocetDni("2005-04-20", "2013-04-30") vráti 2932, ak si odmyslím že neráta aj začiatočný a konečný deň tak by to podľa mojich prepočtov malo byť 2931 (s tými dňami 2933).. predpokladám že problém je v prestupných rokoch ale vôbec nemám predstavu ako to vyriešiť..

ďakujem za prípadnú radu, námet..


poznámka, funkciu datediff použiť nemôžem verzia php je 5.2...


a ďalšia vec je že by som v prípade že počet dní je väčší ako rok, potreboval urobiť prevod na roky a zbytok v dňoch napr. pocetDni("2013-03-30", "2013-04-30") a výsledok by bol 8 rokov a xx dní.
ShiraNai7
Profil
Vyzkoušej tohle. Funkce vrací pole. První prvek (0) je počet roků, druhý (1) počet dnů.
Formátování do řetězce "x roků a x dnů" nechám na tobě.

Použít ji můžeš například takto: list($roky, $dny) = pocetDni('datum od zde', 'datum do zde');

function pocetDni($from, $to)
{
    $from = new DateTime($from);
    $to = new DateTime($to);
    $fromYear = $from->format('Y');
    $toYear = $to->format('Y');
    $fromDay = 1 + $from->format('z');
    $toDay = 1 + $to->format('z');

    if ($toYear < $fromYear || $toYear == $fromYear && $toDay < $fromDay) {
        throw new InvalidArgumentException('Invalid dates - "to" must be greater than or equal to "from"');
    }

    if ($toYear === $fromYear) {
        return array(0, 1 + $toDay - $fromDay);
    } else {
        $yearCount = $toYear - $fromYear - 1;
        $dayCount = date('z', mktime(12, 0, 0, 12, 31, $fromYear)) - $fromDay + $toDay;
        if ($dayCount == date('z', mktime(12, 0, 0, 12, 31, $toYear))) {
            $dayCount = 0;
            ++$yearCount;
        } elseif ($dayCount >= 365) {
            $yearCount += floor($dayCount / 365);
            $dayCount %= 365;
        }
        return array($yearCount, $dayCount);
    }
}

Zkouška:
var_dump(pocetDni('2013-03-30', '2013-04-30'));

Výsledek:
array(2) {
  [0]=>
  int(0)
  [1]=>
  int(32)
}

Zkouška:
var_dump(pocetDni('2013-03-30', '2014-04-30'));

Výsledek:
array(2) {
  [0]=>
  int(0)
  [1]=>
  int(395)
}

Zkouška:
var_dump(pocetDni('1999-03-01', '2013-03-01'));

Výsledek:
array(2) {
  [0]=>
  int(14)
  [1]=>
  int(0)
}
Joker
Profil
ShiraNai7:
Ta funkce ale nebere ohled na přestupné roky.
Například od 1. 3. 1999 do 1. 3. 2013 je to přesně 14 let, ale ta funkce vrátí 14 let a 5 dní.

Krom toho „První prvek (0) je počet roků nebo null“ je podivný mechanismus fungování, očekával bych, že to bude prostě počet roků (tj. žádný rok bude 0).
Marecek
Profil *
Díky ShiraNai7, ale nefunguje to tak ako Joker píše..
Camo
Profil
Môžem sa spýtať, prečo je problém tam pričítať tie dva dni?

A aby som aj niečím prispel, tak je tu ešte taká exotická možnosť použiť MySQL.
SELECT DATEDIFF('2013-3-1','1999-3-1') AS DiffDate;
A v manuáli sa to rieši hneď v prvom príklade ako vidím. Autor tvrdí, že to funguje aj s prestupnými rokmi.
ShiraNai7
Profil
Joker, Marecek:

Funkci jsem upravil. Teď vrací počet skutečných kalendářních roků (nebo 0) v daném rozsahu a počet dnů.
Pro rozsah 1. 3. 1999 do 1. 3. 2013 už vrací 14 let a 0 dnů.
Marecek
Profil *
Camo:
Môžem sa spýtať, prečo je problém tam pričítať tie dva dni?
nie je to problém, ale nepríde mi to ako systémové riešenie.. skôr ako taká záplata. Vyriešiť tie dva dni viem, skôr išlo o tú prácu s prestupným rokom

A aby som aj niečím prispel, tak je tu ešte taká exotická možnosť použiť MySQL.
nechcel som to riešiť v db

ShiraNai7:
Funkci jsem upravil. Teď vrací počet skutečných kalendářních roků (nebo 0) v daném rozsahu a počet dnů.
vďaka, vážne si cením snahu, ale nie je to ono, od 01.04.2006 do 14.04.2011 vráti 4 roky a 377 dní, čo sám musíš uznať že je kravina..

Moje aktuálne riešenie je poskladané s funkcie ktorú som našiel tu a nejakých mojich poznatkov, ktoré som vypátral..

 function pocetDni($start, $end) 
  {
      $day = 86400; 
      $sTime = strtotime($start);
      $eTime = strtotime($end); 
      $pocet = round(($eTime - $sTime) / $day) + 1;
      if(($pocet /365.25) >= 1)
     {
         $roky = floor($dni/365.25);
         $pocet = $pocet - ($roky * 365.25);
     }
     else
     {
       $roky = "0";
     }
     return array($roky, $pocet);      
  }   

Výsledky vyzerajú relatívne uveriteľne ale nie som si tým 100% istý..
ShiraNai7
Profil
Marecek:
od 01.04.2006 do 14.04.2011 vráti 4 roky a 377 dní, čo sám musíš uznať že je kravina..

Není to kravina, když počítáš jen skutečné kalendářní roky .. například 370 dní od poloviny tohoto roku je sice doba delší než 1 rok, ale celý kalendářní rok za to dobu neuplynul.

Funkci jsem upravil, aby v tomto případě připočetla roky podle počet dnů / 365 (je to počet dnů napříč několika roky, v tomto případě nedává smysl brát ohled na přestupné roky).


var_dump(pocetDni('2006-04-01', '2011-04-14'));

Výsledek:
array(2) {
  [0]=>
  float(5)
  [1]=>
  int(12)
}


Výsledky vyzerajú relatívne uveriteľne ale nie som si tým 100% istý..

To nebuď.. na řádku 5 máš $dni namísto $pocet a nepočítáš s přestupnými roky. Nevím, proč jsi tedy pozitivně reagoval v #4 na Jokerovu poznámku o přestupných rocích a psal „skôr išlo o tú prácu s prestupným rokom
když teď na ně kašleš taky.

Výsledky tvé funkce (líta ti to +- den nebo víc):

var_dump(pocetDni('2006-04-01', '2011-04-14'));
/*
array(2) {
  [0]=>
  float(5)
  [1]=>
  float(13.75)
}
*/

var_dump(pocetDni('1999-03-01', '2013-03-01'));
/*
array(2) {
  [0]=>
  float(14)
  [1]=>
  float(1.5)
}
*/
Majkl578
Profil
Proč takové složitosti? Nestačí použít DateTime a diff?
$from = '2011-04-01';
$to = '2012-04-01';


$fromDT = new \DateTime($from);
$toDT = new \DateTime($to);

$diff = $toDT->diff($fromDT);

var_dump($diff->days); // 366 - přestupní rok je zohledněn

-----

Aha, až teď jsem si všiml, že je to pro staré PHP (5.2). Pardon.
Joker
Profil
ShiraNai7:
Není to kravina, když počítáš jen skutečné kalendářní roky .. například 370 dní od poloviny tohoto roku je sice doba delší než 1 rok, ale celý kalendářní rok za to dobu neuplynul.
To je svým způsobem pravda, ale běžně se takhle délka roku neurčuje.
Ale přístup v té opravené verzi by měl být funkční, byť tu implementaci jsem detailně nezkoumal.

Marecek:
„Môžem sa spýtať, prečo je problém tam pričítať tie dva dni?“
nie je to problém, ale nepríde mi to ako systémové riešenie.. skôr ako taká záplata.
Proč?
Je to nejjednodušší řešení a neměl by s ním být žádný problém. A použít existující funkčnost pro výpočet dnů „mezi“ a potom připočíst ty krajní dny intervalu je určitě systémovější, než celý ten výpočet duplikovat.

Majkl578:
Proč takové složitosti? Nestačí použít DateTime a diff?
To píše hned na začátku, že na to nemá dost vysokou verzi PHP.
Enko
Profil *
Pokud je to ještě aktuální, našel jsem svoje několik let staré řešení. Posílám to komplet včetně použití.
<?php
function get_time_difference($start, $end){
  $uts['start'] = strtotime($start);
  $uts['end'] = strtotime($end);
  if($uts['start'] !== -1 && $uts['end'] !== -1){
    if($uts['end'] >= $uts['start']){
      $diff = $uts['end'] - $uts['start'];
      if($days = intval((floor($diff / 86400))))
        $diff = $diff % 86400;
      if($hours = intval((floor($diff / 3600))))
        $diff = $diff % 3600;
      if($minutes = intval((floor($diff / 60))))
        $diff = $diff % 60;
        $diff = intval($diff);            
    return(array('days'=>$days, 'hours'=>$hours, 'minutes'=>$minutes, 'seconds'=>$diff));
    }
    else{
    //trigger_error("Konečný datum a čas je starší než počáteční!", E_USER_WARNING);
    }
  }
  else{
    //trigger_error("Zjištěno neplatné datum nebo čas!", E_USER_WARNING);
  }
  return(false);
}

//$row["end"] je datum konce a musi byt ulozena v numerickem formatu YYYY-MM-DD-HH-MM-SS
$datum = explode("-", $row["end"]);
$rok = $datum[0];
$mesic = $datum[1];
$den = $datum[2];
$hodina = $datum[3];
$minuta = $datum[4];
$sekunda = $datum[5]; 

$arr = get_time_difference("now", "$rok-$mesic-$den $hodina:$minuta:$sekunda");
//echo "Aukce konci ";
//echo $den.". ".$mesic.". ".$rok." ".$hodina.":".$minuta.":".$sekunda;
if($arr == false){ 
  echo "Prodáno";
}

else{
  //nastaveni pádu ke dnům
  if($arr["days"] == "1"){$dny = "den";}
  elseif($arr["days"] == "2" or $arr["days"] == "3" or $arr["days"] == "4"){$dny = "dny";}
  else{$dny = "dnů";}
  //nastavení pádu k hodinám
  if($arr["hours"] == "1"){$hodin = "hodina";}
  elseif($arr["hours"] == "2" or $arr["hours"] == "3" or $arr["hours"] == "4"){$hodin = "hodiny";}
  else{$hodin = "hodin";}
  //nastavení pádu k minutám
  if($arr["minutes"] == "1"){$minut = "minuta";}
  elseif($arr["minutes"] == "2" or $arr["minutes"] == "3" or $arr["minutes"] == "4"){$minut = "minuty";}
  else{$minut = "minut";}
  //nastavení pádu k sekundám
  if($arr["seconds"] == "1"){$sekund = "sekunda";}
  elseif($arr["seconds"] == "2" or $arr["seconds"] == "3" or $arr["seconds"] == "4"){$sekund = "sekundy";}
  else{$sekund = "sekund";}

  //konec bude za
  if($arr["days"] > 0){
    echo $arr["days"]. $dny ;
    echo " a ";
    echo $arr["hours"]. $hodin ;
  }
  elseif($arr["hours"] > 0){ 
    echo $arr["hours"]. $hodin ;
    echo " a ";
    echo $arr["minutes"]. $minut ;
  }  
  elseif($arr["minutes"] > 0){
    echo $arr["minutes"]. $minut ;
    echo " a ";
    echo $arr["seconds"]. $sekund ;
  }
  else{  
    echo $arr["seconds"]. $sekund ;
  }
}
?>
Marecek
Profil *
Dík moc, všem hlavne ShiraNai7.

To Enko: skúsim aj toto riešenie, už len tak zo zvedavosti.. dík

Joker:
Proč?
Je to nejjednodušší řešení a neměl by s ním být žádný problém. A použít existující funkčnost pro výpočet dnů „mezi“ a potom připočíst ty krajní dny intervalu je určitě systémovější, než celý ten výpočet duplikovat.
Nemyslel som niečo duplikovať, ide len o princípe.. nemám rád záplatovanie (ako to robí windows, urobia hotový systém, potom prídu na chybu a záplatujú). Mne osobne to tak príde. V tom vlákne odkiaľ som čerpal je funkcia ktorý načíta všetky dni medzi termínami do pola a následne ich zráta čím rovno povie presný počet dní.. to mi príde skôr ako systémové riešenie ale áno rozumiem čo píšeš.. je to len taký detail, na ktorý sa môže naše názory líšiť..
Camo
Profil
Marecek:
Pričítať 2 nieje chyba.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: