Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Ilość dni pomiędzy datami (bez weekendów !)
Forum PHP.pl > Forum > Przedszkole
bogusborek
Witam,

chcę obliczyć różnicę wyrażoną w dniach pomiędzy dwiema datami (ale bez sobót i niedziel) czyli tylko dni robocze. Używam poniższych funkcji, jednak tam są liczone wszystkie dni.

  1. $wynik = roznicamiedzydatami(uniksowy_znacznik_czasu($start, $koniec));
  2. echo $wynik[1];



  1. //***************************************************************************//
  2. //** ROZNICA MIEDZY UNIKSOWYMI ZNACZNIKAMI CZASU **//
  3. //***************************************************************************//
  4. function uniksowy_znacznik_czasu($start, $koniec)
  5. {
  6. $start = strtotime($start);
  7. $koniec = strtotime($koniec);
  8. return $koniec-$start;
  9. }
  10.  
  11.  
  12. //***************************************************************************//
  13. //** ROZNICA MIEDZY UNIKSOWYMI ZNACZNIKAMI WYRAZONA SLOWNIE **//
  14. //***************************************************************************//
  15. function roznicamiedzydatami($czas) {
  16. $wynik = array();
  17. $tydzien = 7*24*60*60;
  18. $dzien = 24*60*60;
  19. $godzina = 60*60;
  20. $minuta = 60;
  21. if (($wynik[0] = intval($czas/$tydzien)))
  22. $czas %= $tydzien;
  23. if (($wynik[1] = intval($czas/$dzien)))
  24. $czas %= $dzien;
  25. if (($wynik[2] = intval($czas/$godzina)))
  26. $czas %= $godzina;
  27. $wynik[3] = intval($czas/$minuta);
  28. return $wynik;
  29. }
cve
Aleś namieszał smile.gif niepotrzebnie tyle kodu, proszę bardzo:
  1. function countOfWorkingDays($dateStart, $dateEnd) {
  2. $start = strtotime($dateStart);
  3. $end = strtotime($dateEnd);
  4. $result = 0;
  5. for($i=$start; $i<=$end; $i+=86400) {
  6. $fullDate = getdate($i);
  7. $nameOfDay = $fullDate['weekday'];
  8. if($nameOfDay != 'Saturday' && $nameOfDay != 'Sunday')
  9. $result++;
  10. }
  11. return $result;
  12. }
  13.  
  14. //i przyklad do sprawdzenia od 1 stycznia nowego roku do 10 daje 6 dni bez sobot i niedziel prawda?
  15. echo countOfWorkingDays('1 January 2010', '10 January 2010');

troszeczke sie nad tym mozna bylo poglowic jakas godzina...
Mozna oczywiscie zabezpieczyc sie przed nieoczekiwanymi typami danych itp, ale to juz sobie zrobisz, np. mozna dodac instrukcje ktora zawsze odejmie od siebie date wieksza od mniejszej, zeby nie bylo cyrkow, bo jak ktos poda odwrotna kolejnosc dat w parametrach funkcji to sie mamy blad.
magnus
Ja zrobiłem nieco inaczej smile.gif
Potrzebowałem zliczać dni robocze pomiędzy dwoma datami, z tym że:
- uwzględniając również święta,
- biorąc pod uwagę godzinę, przy czym nie doliczać dnia, jeśli początkowa data jest po godzinie 15-tej.
Dni wolne postanowiłem trzymać w bazie danych.

Pierwsza wersja funkcji (parametr 'rob' określa czy liczyć kalendarzowe czy robocze):
  1. function dni_rob($data, $rob = true) {
  2.  
  3. if (!$data) {
  4. return 'ND';
  5. }
  6.  
  7. $data_od = substr($data, 0, 10);
  8. $data_do = date('Y-m-d');
  9.  
  10. $dni = (strtotime($data_do) - strtotime($data_od))/(60*60*24);
  11.  
  12. //jeśli po 15-tej odejmij jeden dzień
  13. if ((date("G", strtotime($data)) > 15)) {
  14. $dni--;
  15. }
  16.  
  17. if ($rob) {
  18.  
  19. $q = Doctrine_Query::create()->select('h.*')->from('Holidays h')->where('h.data >= ?', $data_od)->andWhere('h.data <= ?', $data_do);
  20. $h = $q->execute(array(), Doctrine::HYDRATE_SCALAR);
  21.  
  22. $dni = $dni - count($h);
  23.  
  24. }
  25.  
  26. if ($dni < 0) $dni = 0; //może wyjść -1
  27.  
  28. return $dni;
  29.  
  30. }


Działa. Jednak średnio na każdej stronie wywołuję to 10 razy. Można spróbować oszczędzić liczbę zapytań. Tak powstała druga wersja:

  1. function dni_rob($data, $rob = true) {
  2.  
  3. $cache= Cache::instance();
  4.  
  5. if (!$data) {
  6. return 'ND';
  7. }
  8. $data_od = substr($data, 0, 10);
  9. $data_do = date('Y-m-d');
  10.  
  11. $dni = (strtotime($data_do) - strtotime($data_od))/(60*60*24);
  12.  
  13. if ((date("G", strtotime($data)) > 15)) {
  14. $dni--;
  15. }
  16.  
  17. if ($rob) {
  18.  
  19. //sprawdzam w keszu istnienie tabeli z datami do dzisiaj
  20. $t_dni_robocze = $cache->get('rob_'.$data_do);
  21.  
  22. if (!$t_dni_robocze) {
  23.  
  24. $q = Doctrine_Query::create()->select('h.data')->from('Holidays h')->where('h.data <= ?', $data_do)->orderBy('h.data');
  25. $t_dni_robocze = $q->execute(array(), Doctrine::HYDRATE_SCALAR);
  26.  
  27. //cache na 24 godziny
  28. $cache->set('rob_'.$data_do, $t_dni_robocze, array(), 60*60*24);
  29.  
  30. }
  31.  
  32. foreach ($t_dni_robocze as $k=>$v) {
  33.  
  34. if ($k >= $data_od && $k <= $data_do) {
  35. $dni--;
  36. }
  37.  
  38. }
  39.  
  40. }
  41.  
  42. if ($dni < 0) $dni = 0;
  43.  
  44. return $dni;
  45.  
  46. }


Oszczędzamy bazę, korzystamy z keszu. Natomiast sam jestem ciekaw czy to jest dużo lepsze rozwiązanie.
A może da się to zrobić lepiej?
nospor
Jakis czas temu splodzilem taki skrypt
http://nospor.pl/liczba-dni-roboczych-n23.html
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.