Exempel på problemlösning - Skottår

I denna artikeln bygger vi vidare på exempel 1, men nu ska vi ta hänsyn till skottår.

Roffe är förbannad. Vad sköen ska jag med en datumhanterare till som inte tar hänsyn till skottår?! Och han har ju faktiskt en poäng med det, skottår spelar ju faktiskt en ganska stor roll i en kalender, så vi får väll lägga ta hänsyn till skott år i vår kod.

Vi ser direkt att det enda som behöver ändras i vår kod för att ta hänsyn till skottår är funktionen antalDagarIMånad. När den anropas behöver vi även veta vilket år det handlar om, så överallt där vi anropar funktionen behöver vi även skicka med året som en parameter. Sedan behöver vi veta om det är skottår det året eller inte. Om vi antar att vi har funktionen ärSkottår, skulle vår kod kunna se ut såhär:

PHP - PHP: Hypertext Preprocessor
<?php // Funktion som skapar ett nytt datum function nyttDatum($år, $månad, $dag){ $datum = array( 'år' => $år, 'månad' => $månad, 'dag' => $dag ); return $datum; } // Funktion som gör om ett datum till en sträng function datumTillSträng($datum){ $sträng = $datum['år'].'-'; if($datum['månad'] < 10){ $sträng .= '0'; } $sträng .= $datum['månad'].'-'; if($datum['dag'] < 10){ $sträng .= '0'; } $sträng .= $datum['dag']; return $sträng; } // Funktion som returnerar antalet dagar i angiven månad function antalDagarIMånad($månad, $år){ // Om månaden är februari if($månad == 2){ if(ärSkottår($år)){ return 29; }else{ return 28; } }else{ // Alla övriga månader $antalDagarIMånader = array( 1 => 31, 3 => 31, 4 => 30, 5 => 31, 6 => 30, 7 => 31, 8 => 31, 9 => 30, 10 => 31, 11 => 30, 12 => 31 ); return $antalDagarIMånader[$månad]; } } // Funktion som ökar ett datum med en dag function ökaDatumMedEnDag($datum){ // Skickar även med året $antalDagarIDennaMånaden = antalDagarIMånad($datum['månad']); if($datum['dag'] == $antalDagarIDennaMånaden){ $datum['dag'] = 1; if($datum['månad'] == 12){ $datum['år'] = $datum['år'] + 1; $datum['månad'] = 1; }else{ $datum['månad'] = $datum['månad'] + 1; } }else{ $datum['dag'] = $datum['dag'] + 1; } return $datum; } // Funktion som minskar ett datum med en dag function minskaDatumMedEnDag($datum){ if($datum['dag'] == 1){ if($datum['månad'] == 1){ $datum['år'] = $datum['år'] - 1; $datum['månad'] = 12; }else{ $datum['månad'] = $datum['månad'] - 1; } // Skickar även med året $antalDagarIDennaMånaden = antalDagarIMånad($datum['månad'], $datum['år']); $datum['dag'] = $antalDagarIDennaMånaden; }else{ $datum['dag'] = $datum['dag'] - 1; } return $datum; } // Funktion som ändrar datumet det angivna antalet dagar function ändraDatum($datum, $antalDagar){ if(0 < $antalDagar){ $ökaEllerMinska = true; }else{ $ökaEllerMinska = false; $antalDagar = -$antalDagar } for($i=1; $i<=$antalDagar; $i++){ if($ökaEllerMinska){ $datum = ökaDatumMedEnDag($datum); }else{ $datum = minskaDatumMedEnDag($datum); } } return $datum; } // Skapar det nya datumet 2011-04-13 $datum = nyttDatum(2011, 4, 13); // Subtrahera 5 dagar från datumet $datum = ändraDatum($datum, -5); // Skriver ut datumet echo datumTillSträng($datum); ?>

Om vi nu bara lyckas få till funktionen ärSkottår borde vi vara klara, men hur avgör man om ett år är skottår eller ej? På engelska Wikipedia ser vi algoritmen för det, så vi implementerar den rakt av.

PHP - PHP: Hypertext Preprocessor
<?php // Funktion som skapar ett nytt datum function nyttDatum($år, $månad, $dag){ $datum = array( 'år' => $år, 'månad' => $månad, 'dag' => $dag ); return $datum; } // Funktion som gör om ett datum till en sträng function datumTillSträng($datum){ $sträng = $datum['år'].'-'; if($datum['månad'] < 10){ $sträng .= '0'; } $sträng .= $datum['månad'].'-'; if($datum['dag'] < 10){ $sträng .= '0'; } $sträng .= $datum['dag']; return $sträng; } // Funktion som returnerar antalet dagar i angiven månad function antalDagarIMånad($månad, $år){ if($månad == 2){ if(ärSkottår($år)){ return 29; }else{ return 28; } }else{ $antalDagarIMånader = array( 1 => 31, 3 => 31, 4 => 30, 5 => 31, 6 => 30, 7 => 31, 8 => 31, 9 => 30, 10 => 31, 11 => 30, 12 => 31 ); return $antalDagarIMånader[$månad]; } } // Funktion som ökar ett datum med en dag function ökaDatumMedEnDag($datum){ $antalDagarIDennaMånaden = antalDagarIMånad($datum['månad']); if($datum['dag'] == $antalDagarIDennaMånaden){ $datum['dag'] = 1; if($datum['månad'] == 12){ $datum['år'] = $datum['år'] + 1; $datum['månad'] = 1; }else{ $datum['månad'] = $datum['månad'] + 1; } }else{ $datum['dag'] = $datum['dag'] + 1; } return $datum; } // Funktion som minskar ett datum med en dag function minskaDatumMedEnDag($datum){ if($datum['dag'] == 1){ if($datum['månad'] == 1){ $datum['år'] = $datum['år'] - 1; $datum['månad'] = 12; }else{ $datum['månad'] = $datum['månad'] - 1; } $antalDagarIDennaMånaden = antalDagarIMånad($datum['månad'], $datum['år']); $datum['dag'] = $antalDagarIDennaMånaden; }else{ $datum['dag'] = $datum['dag'] - 1; } return $datum; } // Funktion som ändrar datumet det angivna antalet dagar function ändraDatum($datum, $antalDagar){ if(0 < $antalDagar){ $ökaEllerMinska = true; }else{ $ökaEllerMinska = false; $antalDagar = -$antalDagar } for($i=1; $i<=$antalDagar; $i++){ if($ökaEllerMinska){ $datum = ökaDatumMedEnDag($datum); }else{ $datum = minskaDatumMedEnDag($datum); } } return $datum; } // Funktion som kollar om angivet år är skottår eller ej function ärSkottår($år){ if($år % 400 == 0){ return true; }elseif($år % 100 == 0){ return false; }elseif($år % 4 == 0){ return true; }else{ return false; } } // Skapar det nya datumet 2011-04-13 $datum = nyttDatum(2011, 4, 13); // Subtrahera 5 dagar från datumet $datum = ändraDatum($datum, -5); // Skriver ut datumet echo datumTillSträng($datum); ?>

Som du såg var det inte alls svårt att lägga till funktionalitet till koden vi hade skrivit innan, vilket tyder på att vi har strukturerat upp den på ett bra sätt. Och vi har inte ändrat något på de funktioner som Roffe använder sig av, så all kod han har skrivit innan kommer fungera lika bra nu, men nu tar de även hänsyn till skottår.