Gå til innhold

PHP-utfording, kan du lage en bedre funksjon enn meg?


Anbefalte innlegg

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;

   }

 

 

  • Liker 1
Lenke til kommentar
Videoannonse
Annonse

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 av FraXinuS
Lenke til kommentar
Gjest Slettet+1298342134

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

Bra jobbet begge to :new_woot:

 

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 av xibriz
Lenke til kommentar

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 av Epower
Lenke til kommentar

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 :p)

 

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

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 konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...