xibriz Skrevet 27. mai 2010 Del Skrevet 27. mai 2010 Jeg tenkte kanskje at en liten utfording her på PHP-delen av forumet kan være på sin plass for de som er lei av de (for erfarne) banale spørsmålene som ofte kommer her. Også er jeg litt interessert i hvordan andre programmerere ville løst samme oppgaven. NB! Dette er ikke en skoleoppgave eller lignende. Jeg har allerede laget funksjonen (se spoiler), jeg er kun ute etter å se andre/bedre løsninger. Funksjonen er en del av noe større. Oppgaven: Finn antall hele halvtimer mellom to gitte klokkeslett. Halvtimene defineres i to grupper. Gruppe 1: 0700 til 2100 Gruppe 2: 2100 til 0700 Hvis en halvtime går over kl 07 skal den legges til gruppe 2. Hvis en halvtime går over kl 21 skal den legges til gruppe 2. I utgangspunktet vil funksjonen bli foret med tall der hele halvtimer går opp, men man må ta høyde for feil. To like klokkeslett vil aldri forekomme. Eksempler på inndata og resultat: 17:00 - 21:30 = 4 timer i gruppe 1 og 0.5 time i gruppe 2 20:35 - 01:05 = 4.5 timer i gruppe 2 06:05 - 08:05 = 1 time i gruppe 1 og 1 time i gruppe 2 Somebody's up for the challenge? private function convertTimeInGroups($timeFrom, $timeTo) { $countHours0700To2100 = 0; //Antall timer mellom kl. 1700 - 2100 $countHours2100To0700 = 0; //Antall timer mellom kl. 2100 - 0700 //Splitter tidene til array $timeFromArr = split("[:]", $timeFrom); $timeToArr = split("[:]", $timeTo); $boolRunTwice = true; $count = 0; //Vi må i verste fall kjøre denne løkken 2 ganger while ($boolRunTwice) { //Hvis start-tiden er mindre eller lik slutt-tiden if (intval($timeFromArr[0]) <= intval($timeToArr[0])) { //Så lenge start-timen er mindre eller lik slutt-timen while (intval($timeFromArr[0]) <= intval($timeToArr[0])) { //Hvis vi får lik tid er vi i mål if (intval($timeFromArr[0]) == intval($timeToArr[0]) && intval($timeFromArr[1]) == intval($timeToArr[1])) { $boolRunTwice = false; break; } //Hvis start-timen er større eller lik kl. 07 og mindre enn kl. 21 if (intval($timeFromArr[0]) >= 7 && intval($timeFromArr[0]) < 21) { //Hvis start-timen er kl. 20 og de neste 30 minuttene dytter oss over til kl. 21, skal vi ha tillegget som starter kl. 21 if (intval($timeFromArr[0]) == 20 && intval($timeFromArr[1]) > 30) $countHours2100To0700 += 0.5; //Hvis ikke skal vi ha tillegget mellom 1700 og 2100 else $countHours0700To2100 += 0.5; } //Hvis start-timen er mindre enn 07 eller større enn 21 skal vi ha tillegget mellom 2100 og 0700 else { $countHours2100To0700 += 0.5; } //Hvis start-minuttene er mindre enn 30 kan vi trygt plusse på 30 minutter if (intval($timeFromArr[1]) < 30) $timeFromArr[1] += 30; //Hvis ikke må vi inkrementere start-timen og trekke fra 30 minutter (det kan hende vi får en rest, eks 45-30 = 15 minutter over neste time) else { $timeFromArr[0] += 1; $timeFromArr[1] = ($timeFromArr[1] - 30); } //Hvis start-timen kommer over kl. 23 må vi starte på 00 if (intval($timeFromArr[0]) > 23) $timeFromArr[0] = 0; } } //Hvis start-tiden er større enn slutt-tiden (arbeid over midnatt) else { //Så lenge start-timen er større eller lik slutt-timen while (intval($timeFromArr[0]) >= intval($timeToArr[0])) { //Hvis vi får lik tid er vi i mål if (intval($timeFromArr[0]) == intval($timeToArr[0]) && intval($timeFromArr[1]) == intval($timeToArr[1])) { $boolRunTwice = false; break; } //Hvis start-timen er større eller lik kl. 07 og mindre enn kl. 21 if (intval($timeFromArr[0]) >= 7 && intval($timeFromArr[0]) < 21) { //Hvis start-timen er kl. 20 og de neste 30 minuttene dytter oss over til kl. 21, skal vi ha tillegget som starter kl. 21 if (intval($timeFromArr[0]) == 20 && intval($timeFromArr[1]) > 30) $countHours2100To0700 += 0.5; //Hvis ikke skal vi ha tillegget mellom 1700 og 2100 else $countHours0700To2100 += 0.5; } //Hvis start-timen er mindre enn 07 eller større enn 21 skal vi ha tillegget mellom 2100 og 0700 else { $countHours2100To0700 += 0.5; } //Hvis start-minuttene er mindre enn 30 kan vi trygt plusse på 30 minutter if (intval($timeFromArr[1]) < 30) $timeFromArr[1] += 30; //Hvis ikke må vi inkrementere start-timen og trekke fra 30 minutter (det kan hende vi får en rest, eks 45-30 = 15 minutter over neste time) else { $timeFromArr[0] += 1; $timeFromArr[1] = ($timeFromArr[1] - 30); } //Hvis start-timen kommer over kl. 23 må vi starte på 00 if (intval($timeFromArr[0]) > 23) $timeFromArr[0] = 0; } } //Sikkerhet for å ikke gå i en uendelig løkke if ($count > 2) $boolRunTwice = false; $count++; } //Antall timer mellom 0700 og 2100 kan aldri bli mer enn 14 med mindre inndataen er feil (ikke hele halvtimer mellom tidene, funksjonen går en ekstra loop) if ($countHours0700To2100 > 14) $countHours0700To2100 = 0; //Antall timer mellom 2100 og 0700 kan aldri bli mer enn 14 med mindre inndataen er feil (ikke hele halvtimer mellom tidene, funksjonen går en ekstra loop) if ($countHours2100To0700 > 11) $countHours2100To0700 = 0; } 1 Lenke til kommentar
FraXinuS Skrevet 27. mai 2010 Del Skrevet 27. mai 2010 (endret) Her er mitt forslag: function convertTimeInGroups($from, $to) { $from = DateTime::createFromFormat('H:i', $from); $to = DateTime::createFromFormat('H:i', $to); if($to < $from) $to->modify('+1 day'); $normal_start = DateTime::createFromFormat('H:i', '07:00'); $normal_end = DateTime::createFromFormat('H:i', '20:31'); $normal_start2 = clone $normal_start; $normal_start2->modify('+1 day'); $normal_end2 = clone $normal_end; $normal_end2->modify('+1 day'); $diff = $to->diff($from); $half_hours = $diff->format('%H')*2 + floor($diff->format('%i')/30); $groups = array(0.0, 0.0); for($i=0; $i < $half_hours; ++$i, $from->modify('+30 minutes')){ if(($from >= $normal_start and $from < $normal_end) or ($from >= $normal_start2 and $from < $normal_end2)) $groups[0] += 0.5; else $groups[1] += 0.5; } return $groups; } Edit: Fikset feil med verdier av denne typen: 22:00 - 09:00 Endret 27. mai 2010 av FraXinuS Lenke til kommentar
Gjest Slettet+1298342134 Skrevet 27. mai 2010 Del Skrevet 27. mai 2010 Min versjon i halvsøvne! <?php function convertTimeInGroups($tStart, $tStop, $lower="07:00", $upper="21:00") { $start = strtotime($tStart); $diff = strtotime($tStop) - $start; $lLimit = strtotime($lower); $uLimit = strtotime($upper); $halfs = ($diff > 0) ? intval($diff/1800) : intval(($diff+(24*3600))/1800); $time = Array('A' => Array(), 'B' => Array()); for($i=1;$i<=$halfs;++$i,$start+=1800) { if((($start + 1800 <= $uLimit) AND ($start >= $lLimit)) OR (($start-$lLimit)/3600 >= 24)) $time['A'][] = $i; else $time['B'][] = $i; } return $time; } ?> Gir det her resultatet Gruppe A: 0700 til 2100 Gruppe B: 2100 til 0700 convertTimeInGroups("05:00","05:00") // 1 døgn Halvtimer i Gruppe A 28 Halvtimer i Gruppe B 20 La nummer på halvtimene i et array så får en se hvordan det blir delt opp mellom gruppene også, istedenfor kun en kjedelig teller. Array ( [A] => Array ( [0] => 5 [1] => 6 [2] => 7 [3] => 8 [4] => 9 [5] => 10 [6] => 11 [7] => 12 [8] => 13 [9] => 14 [10] => 15 [11] => 16 [12] => 17 [13] => 18 [14] => 19 [15] => 20 [16] => 21 [17] => 22 [18] => 23 [19] => 24 [20] => 25 [21] => 26 [22] => 27 [23] => 28 [24] => 29 [25] => 30 [26] => 31 [27] => 32 ) [b] => Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 33 [5] => 34 [6] => 35 [7] => 36 [8] => 37 [9] => 38 [10] => 39 [11] => 40 [12] => 41 [13] => 42 [14] => 43 [15] => 44 [16] => 45 [17] => 46 [18] => 47 [19] => 48 ) ) Tror det blir rett for alle input verdier, men mulig jeg har glemt noen:( Lenke til kommentar
xibriz Skrevet 28. mai 2010 Forfatter Del Skrevet 28. mai 2010 (endret) Bra jobbet begge to Det er godt å studere andre eksempler å lære seg nye teknikker, istedet for å sitte i sin egen lille boble å tro man er best i verden EDIT: Jeg har imidlertid måttet endret min funksjon. I ettertid har jeg funnet ut at jeg må ta høyde for datoen til start tiden, og gruppere det opp i enda flere halvtimer. Endret 28. mai 2010 av xibriz Lenke til kommentar
Epower Skrevet 28. mai 2010 Del Skrevet 28. mai 2010 (endret) Gjorde et forsøk her. Føler jeg har gjort noe helt feil. print_r(find_hours("0730", "2130")); function find_hours($start, $end) { for($i = $start; { if($i > 700 && $i <= 2100) $group1 += 0.5; elseif($i > 2100 || $i <= 700) $group2 += 0.5; if($i == $end) break; elseif($i == 2330) $i = 0; elseif($i % 100 == 0) $i += 30; else $i += 70; } return array($group1, $group2); } Endret 28. mai 2010 av Epower Lenke til kommentar
xibriz Skrevet 28. mai 2010 Forfatter Del Skrevet 28. mai 2010 Gjorde et forsøk her. Føler jeg har gjort noe helt feil. Du kan jo teste 2200 til 0200 Lenke til kommentar
Epower Skrevet 28. mai 2010 Del Skrevet 28. mai 2010 Selvfølgelig, visste jeg hadde glemt noe. Redigerte orginalposten min. Lenke til kommentar
xibriz Skrevet 30. mai 2010 Forfatter Del Skrevet 30. mai 2010 Reglene har blitt endret, og siden det forrige forslaget mitt var crap, har jeg laget en ny funksjon litt inspirert av forslagene over (vet ikke hvorfor jeg ikke gjorde det slik først, skylder på at det ikke er lett å få oversikten mens man sitter nedgravd i regler for hvordan utregningen skal være ) Vi får inn en dato som tilhører fratiden, og en inntid. Inntiden vil aldri være mer enn 24-timer fra starttiden, og skjelden i nærheten av dette. Vi må sørge for at forskjellen mellom fratiden og inntiden går opp i hele halvtimer. Vi må ta høyde for tidsrom på datoen vi får inn, og de samme tidsrom neste dag. Tidsrommet må deles inn i følgende grupper: 0000-0700 0700-1600 1600-1700 1700-2100 2100-0000 Hvis en halvtime går over ett av disse tidsrommene, tilhører den det tidsrommet den startet i. function convertTimeInGroups($date, $timeFrom, $timeTo) { //Antall timer denne dagen $countHoursThisDayArr = array( "0000to0700" => 0, //Antall timer mellom kl. 0000 (midnatt) og 0700 "0700to1600" => 0, //Antall timer mellom kl. 0700 og 1600 "1600to1700" => 0, //Antall timer mellom kl. 1600 og 1700 "1700to2100" => 0, //Antall timer mellom kl. 1700 og 2100 "2100to0000" => 0 //Antall timer mellom kl. 2100 og 0000 (midnatt) ); //Antall timer neste dag $countHoursNextDayArr = array( "0000to0700" => 0, //Antall timer mellom kl. 0000 (midnatt) og 0700 "0700to1600" => 0, //Antall timer mellom kl. 0700 og 1600 "1600to1700" => 0, //Antall timer mellom kl. 1600 og 1700 "1700to2100" => 0, //Antall timer mellom kl. 1700 og 2100 "2100to0000" => 0 //Antall timer mellom kl. 2100 og 0000 (midnatt) ); $timestampDate = strtotime($date); $timestampNextDate = strtotime("+1 day", $timestampDate); $timestamp0700 = strtotime("07:00", $timestampDate); $timestamp1600 = strtotime("16:00", $timestampDate); $timestamp1700 = strtotime("17:00", $timestampDate); $timestamp2100 = strtotime("21:00", $timestampDate); $timestamp0000Next = strtotime("00:00", $timestampNextDate); $timestamp0700Next = strtotime("07:00", $timestampNextDate); $timestamp1600Next = strtotime("16:00", $timestampNextDate); $timestamp1700Next = strtotime("17:00", $timestampNextDate); $timestamp2100Next = strtotime("21:00", $timestampNextDate); $timestampFrom = strtotime($timeFrom, $timestampDate); $timestampTo = strtotime($timeTo, $timestampDate); if ($timestampTo < $timestampFrom) { $timestampTo = strtotime($timeTo, $timestampNextDate); } //Sørger for å justere opp til nermeste hele halvtime if (intval(($timestampTo-$timestampFrom)%1800) != 0) $timestampTo += (1800-(($timestampTo-$timestampFrom)%1800)); //Går gjennom hver halvtime mellom fra og til-tiden og inkrementerer riktig index i riktig array med 0.5 for hver halvtime for ($timestamp = $timestampFrom; $timestamp < $timestampTo; $timestamp += 1800) { if ($timestamp < $timestamp0700) $countHoursThisDayArr["0000to0700"] += 0.5; else if ($timestamp < $timestamp1600) $countHoursThisDayArr["0700to1600"] += 0.5; else if ($timestamp < $timestamp1700) $countHoursThisDayArr["1600to1700"] += 0.5; else if ($timestamp < $timestamp2100) $countHoursThisDayArr["1700to2100"] += 0.5; else if ($timestamp < $timestamp0000Next) $countHoursThisDayArr["2100to0000"] += 0.5; else if ($timestamp < $timestamp0700Next) $countHoursNextDayArr["0000to0700"] += 0.5; else if ($timestamp < $timestamp1600Next) $countHoursNextDayArr["0700to1600"] += 0.5; else if ($timestamp < $timestamp1700Next) $countHoursNextDayArr["1600to1700"] += 0.5; else if ($timestamp < $timestamp2100Next) $countHoursNextDayArr["1700to2100"] += 0.5; else $countHoursNextDayArr["2100to0000"] += 0.5; } } Har ikke testet dette 100% enda, men det ser greit ut Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå