Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [PHP]Ilość dni pomiędzy datami (bez weekendów !)
bogusborek
post 6.01.2010, 23:31:51
Post #1





Grupa: Zarejestrowani
Postów: 10
Pomógł: 1
Dołączył: 6.01.2010

Ostrzeżenie: (0%)
-----


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. }
Go to the top of the page
+Quote Post
cve
post 7.01.2010, 01:20:17
Post #2





Grupa: Zarejestrowani
Postów: 25
Pomógł: 0
Dołączył: 18.09.2009

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
magnus
post 7.01.2010, 11:03:15
Post #3





Grupa: Zarejestrowani
Postów: 99
Pomógł: 15
Dołączył: 15.11.2007
Skąd: Nowogród Bobrz.

Ostrzeżenie: (0%)
-----


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?


--------------------
Efemental.pl - nasz punkt słyszenia :: recenzje :: tylko metal!
Opensource'owy klon Cantra: http://github.com/magnax/Simtr
Go to the top of the page
+Quote Post
nospor
post 7.01.2010, 11:07:31
Post #4





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Jakis czas temu splodzilem taki skrypt
http://nospor.pl/liczba-dni-roboczych-n23.html


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 18.05.2025 - 08:33