Languages :: PHP :: performance problem with function to calculate time period (incl. workdays) |
|||
| By: peter911 |
Date: 10/06/2003 00:00:00 |
Points: 500 | Status: Answered Quality : Excellent |
|
sorry for multiposting - it's a php question but perhaps a non-php-programmer can help me too... i have a function datesubtr to calculcate the time period of 2 dates - it reckognizes the workdays too. the big problem now is while-loop - it takes too much time to execute (if you test it with a counter in the while-loop you'll see that the while-loop is being executed for 4970949709 times) can anybody optimize the performance of this function or has an alternative idea? many thnx, Peter //parameteres $from and $until are "YYYY-MM-DD" function datesubtr($from,$until){ $tsfrom=strtotime($from); $tsuntil=strtotime($until); $hrsfrom=date("H",$tsfrom); $minfrom=date("i",$tsfrom); $secfrom=date("s",$tsfrom); $hrsuntil=date("H",$tsuntil); $minuntil=date("i",$tsuntil); $secuntil=date("s",$tsuntil); $tsfrom=mktime($hrsfrom,$minfrom,$secfrom,date("m",$tsfrom),date("d",$tsfrom),date("Y",$tsfrom)); $tsuntil=mktime($hrsuntil,$minuntil,$secuntil,date("m",$tsuntil),date("d",$tsuntil),date("Y",$tsuntil)); $timeperiod=$tsuntil-$tsfrom; if (date("D",$tsfrom)=="Sat" || date("D",$tsfrom)=="Sun"){ $timeperiod=$timeperiod-(((24-$hrsfrom)*3600)-($minfrom*60)-$secfrom); } $sdatum=date("Ymd",$tsfrom+86400); $tdatum=$tsfrom+86400; while ($sdatum!=date("Ymd",$tsuntil)){ $wtag=date("D",$tdatum); $feiert=false; if (in_array(date("Y-m-d",$tdatum),$FeiertageDaten["FEIERT_DATUM"])){ $feiert=true; } if ($wtag=="Sat" || $wtag=="Sun" || $feiert==true){ $timeperiod=$timeperiod-86400; } $sdatum=date("Ymd",$tdatum+86400); $tdatum=$tdatum+86400; } if (date("D",$tsuntil)=="Sat" || date("D",$tsuntil)=="Sun"){ $timeperiod=$timeperiod-($hrsuntil*3600)-($minuntil*60)-$secuntil; } return $timeperiod/60/60; } |
|||
| By: VGR | Date: 10/06/2003 00:26:00 | Type : Comment |
|
| ok, this seems a rather strange way to do it. Moreovern you get rid of non-workable days, but you count 24 hours par day , while people rarely are able to work that amount. Let's skip over this. Then I suppose that the array $FeiertageDaten is declared GLOBAL in the function, huh ? For me, it's empty "as is" Iterating so many times si the sure proof there is a conceptual problem. Give me some time |
|||
| By: ThG | Date: 10/06/2003 00:38:00 | Type : Comment |
|
| > while people rarely are able to work that amount. Let's skip over this. seems something that doesn't apply to you :-) |
|||
| By: peter911 | Date: 10/06/2003 00:40:00 | Type : Comment |
|
| plz don't notice the line with $FeiertageDaten and don't mind the if-operator "$feiert==true" - they shouldn't stand there. i've changed the while-line to: while ($sdatum!=date("Ymd",$tsbis) && date("Y",$sdatum)==date("Y")){ now it's fast enough but i don't know if it produces errors - especially when the years of the two dates are different... thnx peter |
|||
| By: ThG | Date: 10/06/2003 00:53:00 | Type : Comment |
|
| peter911: your code as-is kinda work, except when $until is before $from. anyway testing in a loop with != or == is dangerous in this situation. If for any reason the matching point is passed, you get into an infinite loop. You should use <= or >=. anyway there are too many things that doesn't make sense, like: ... while ($sdatum!=date("Ymd",$tsuntil)){ ... $sdatum=date("Ymd",$tdatum+86400); $tdatum=$tdatum+86400; ... why don't you just test $tdatum with $tsuntil?? |
|||
| By: VGR | Date: 10/06/2003 01:25:00 | Type : Comment |
|
| huh huh huh |
|||
| By: VGR | Date: 10/06/2003 01:40:00 | Type : Assist |
|
| ok, here's a result from your code : 1. 172800 2. 172800 3. 20030102 / 1041548400 4. 172800 retourné : 48 called with this : $toto=datesubtr('2003-01-01','2003-01-03'); (two days -> 48 hours, fine) 1st of Jan. is a Wed so you wonsider it workable, while it is almost wordly non-working. What you do - given you don't (yet?) have a 'Ferien Daten' feature - is roughly : -count the number of days being not Sun nor Sat -return 24*this number (yes yes yes, that's what you do) So it can be done differently and more efficiently. 1) tell me if you agree so that I do something for you 2) I've an other suggestion, involving using MySql's perpetual calendar : would you consider accessing MySql for this ? It's a matter of one query :D |
|||
| By: peter911 | Date: 10/06/2003 02:14:00 | Type : Comment |
|
| i've implemented the holiday-problem (from a mysql-table) yet - but this doesn't crash my performance... with the changed while-line it goes really as fast as i'm needing it... thnx peter |
|||
| By: ThG | Date: 10/06/2003 02:34:00 | Type : Comment |
|
i keep thinking you should change your while condition to while ($tdatum < $tsuntil) |
|||
| By: sumotimor | Date: 10/06/2003 03:32:00 | Type : Answer |
|
| Fun problem! This works for me. It uses the dateAdd() function to iterate, first using weeks (with each complete week = 5 work days), then iterating through each day in the last week to add the remainder. The days between is inclusive, so 2003-06-09 to 2003-06-10 would return 2. If you're after hours, just multiply the number of days * work hours in your day. It's reasonably fast, and should be smart about leap-years, daylight savings, etc. If you need it to omit holidays, that gets somewhat messier. <?php function daysBetween($start, $stop) { $days = 0; $start = strtotime($start); // convert YYYY-MM-DD to timestamp $stop = strtotime($stop); // convert YYYY-MM-DD to timestamp echo ("Finding range between " . date ("D Y-m-d", $start) . " through " . date("D Y-m-d", $stop) . "<br />\n"); // add weeks while (($test = dateAdd(7, 0, 0, $start)) <= $stop) { $days += 5; // 5 workdays in a week $start = $test; } // add days //while (($test = dateAdd(1, 0, 0, $start)) <= $stop) { for ($test=$start; $test <= $stop; $test = dateAdd(1, 0, 0, $start)) { if (date('w', $test) != 0 && date('w', $test) != 6) { $days++; } $start = $test; } return $days; } function dateAdd($days, $months=0, $years=0, $start=null) { if (!$start) $start = time(); $now = getDate($start); return mktime($now['hours'], $now['minutes'], $now['seconds'], $now['mon'] + $months, $now['mday'] + $days, $now['year'] + $years); } echo daysBetween("2003-06-03", "2003-06-14"); ?> |
|||
| By: peter911 | Date: 10/06/2003 03:44:00 | Type : Comment |
|
| thnx, i found my mistake - the while-loop was running endless! |
|||
|
Do register to be able to answer |
|||
©2010 These pages are served without commercial sponsorship. (No popup ads, etc...). Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE.
Please DO link to this page!








