[PHP] maandkalender - logisch probleem

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Rexomnium
  • Registratie: September 2000
  • Laatst online: 17-09 16:07

Rexomnium

Vincam aut moriar

Topicstarter
Ik ben bezig om een agenda / kalender te maken die men kan indelen in dagen, weken en maanden.

Het is me gelukt om een weekkalender te maken. Ik kan met behulp van een functie die ik hier heb gevonden de startdatum van een willekeurige week achterhalen en de einddatum. De functie - even ter herhaling - vind je hieronder:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function weektotimestamp($year, $week, $day)
{
    
    $firstdate = mktime (0,0,0,1,4, $year); // jan 04 always in week 1
    $firstday = date("w", $firstdate); // fetch day of week of jan 04
    if ($firstday == 0) 
        { 
            $firstday = 7; 
        }
        
    $offset = ($week-1) * 7 - $firstday + $day; //calc number of days difference from jan 04
    
    return strtotime('+' .$offset .' days', $firstdate);
}


Nu wil ik net zoals in dit plaatje de maanden weer indelen in weken. December 2005 bijvoorbeeld, loopt vanaf donderdag 1 december t/m zaterdag 31 december. Dat is respectievelijk week 48 t/m week 52.

De kalender voor de maand december moet dus beginnen op 28 november 2005 (startdatum week 48) t/m 1 januari 2006 (einddatum week 52). De kalender voor januari 2006 loopt vanaf 26 december 2005 t/m 6 februari 2006.

Nou rijst er een probleem op in de januari kalender. Om de startdatum van de week te bepalen moet ik twee argumenten bij de functie geven, het weeknummer en het jaar. Januari 2006 begint in week 52 van het jaar 2005, maar vanaf 1 januari zitten we in 2006. Uiteraard wordt het jaar 2006 meegegeven aan de functie. Ik kan geen if-statement maken om dat recht te trekken, want ik weet niet hoe het in de volgende jaren gaat lopen. Op onderstaande URL kun je kijken hoe het werkt. Je ziet de startweek en de eindweek staan en een rij data die in die maandkalender zouden moeten komen. Je zult zien dat de maand januari niets weergeeft, aangezien die datum loopt van 20061225 t/m 20060205, wat dus fout is.


Hieronder de code die ik gebruik (om naar de vorige en volgende maand te gaan, gebruik ik index.php?month=$month_prev_month en index.php?month=$month_next_month):
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// Code om volgende en vorige maanden uit te rekenen
                
    $month_first_day = date("Ymd", mktime(0, 0, 0, $this_month, 1, $this_year));
    $month_first_year = date("Y", mktime(0, 0, 0, $this_month, 1, $this_year));
    $month_first_week = date("W", mktime(0, 0, 0, $this_month, 1, $this_year));
    $month_first_week_day = date("Ymd", weektotimestamp($this_year, $month_first_week, 1));
                
    $month_first_day_compare = $month_first_week_day;
                
    $month_last_day = date("Ymd", mktime(0, 0, 0, $this_month+1, 0, $this_year));
    $month_last_year = date("Y", mktime(0, 0, 0, $this_month+1, 0, $this_year));
    $month_last_week = date("W", mktime(0, 0, 0, $this_month+1, 0, $this_year));
    $month_last_week_day = date("Ymd", weektotimestamp($month_last_year, $month_last_week, 7));
                
    $month_prev_month = date("Ymd", mktime(0, 0, 0, $this_month-1, 1, $this_year));
    $month_next_month = date("Ymd", mktime(0, 0, 0, $this_month+1, 1, $this_year)); 
                
?>


PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
    // while loop om data uit te spugen + begindatum en einddatum
        echo "Week ".$month_first_week." ".$month_first_week_day."<br>";
    echo "Week ".$month_last_week." ".$month_last_week_day."<br><br><br><br>";
    $x = 1;
                        
        while ($month_first_day_compare <= $month_last_week_day)
        {
            echo $x.". ".$month_first_day_compare."<br>";
            $month_first_day_compare = date("Ymd", mktime(0, 0, 0, substr($month_first_day_compare, 4, 2), substr($month_first_day_compare, 6, 2)+1, substr($month_first_day_compare, 0, 4)));
            $x++;
        }
                            
?>

Hoe kan ik dit euvel in godsnaam oplossen. Ik ben nu al een week bezig om de oplossing te vinden en ik kom er niet meer uit. Het is geen optie om louter de dagen van de betreffende maand te nemen, ik wil kosten wat het kost de begin- en einddata van de weken hebben.

[ Voor 12% gewijzigd door Rexomnium op 20-12-2005 17:39 ]

We zijn allemaal vaandeldrager in een optocht van gekwetsten.


Acties:
  • 0 Henk 'm!

  • Maxxi
  • Registratie: Mei 2004
  • Laatst online: 19-04 19:18
wtf wil je nou maken?

Acties:
  • 0 Henk 'm!

  • chris
  • Registratie: September 2001
  • Laatst online: 11-03-2022
Je algoritme werkt dus als volgt:
gegeven een maand en een jaar bepaal je de eerste datum van die maand (altijd 1) en de laatste datum (28, 30 of 31). Gegeven die datum ga je kijken in welke week die datum valt. Je kan best een hard-coded check doen als: if maand=januari and week=52 then year = year -1

Vervolgens maak je een functie display_week(weeknummer, jaar) die zo'n week print. Geen probleem?

Acties:
  • 0 Henk 'm!

  • Rexomnium
  • Registratie: September 2000
  • Laatst online: 17-09 16:07

Rexomnium

Vincam aut moriar

Topicstarter
Maanden op week ingedeeld, met als werkelijke startdag de maandag van de week waarin de maand start en als werkelijke einddag de zondag van de week waarin de maand eindigt.

Het spijt me, maar ik kan de zinnen niet helderder maken :)

Voorbeeld december 2005:
December begint in week 48 en eindigt in week 52.
De maandag van week 48 is op 28 november 2005 en de zondag van week 52 is 1 januari 2006.

Voorbeeld januari 2006
Januari begint in week 52, 2005 en eindigt in week 5, 2006.
De maandag van week 52, 2005 begint is op 26 december 2005 en de zondag van week 5 is op 5 februari 2006.

Ik wil simpelweg naar de vorige en volgende maand kunnen gaan...
chris schreef op dinsdag 20 december 2005 @ 16:15:
Je algoritme werkt dus als volgt:
gegeven een maand en een jaar bepaal je de eerste datum van die maand (altijd 1) en de laatste datum (28, 30 of 31). Gegeven die datum ga je kijken in welke week die datum valt. Je kan best een hard-coded check doen als: if maand=januari and week=52 then year = year -1

Vervolgens maak je een functie display_week(weeknummer, jaar) die zo'n week print. Geen probleem?
...dat is inderdaad een mogelijke oplossing, maar hoe zit het dan als een jaar 53 weken heeft?
chris schreef op dinsdag 20 december 2005 @ 16:18:
[...]

Dan doe je if weeknummer >= 52 ? Dat had je best zelf kunnen bedenken, toch?
Ja dat wel, maar ik wilde het even van jou horen.
Nee, ja, je hebt gelijk, ik ga dat even proberen.

[ Voor 38% gewijzigd door Rexomnium op 20-12-2005 16:20 ]

We zijn allemaal vaandeldrager in een optocht van gekwetsten.


Acties:
  • 0 Henk 'm!

  • chris
  • Registratie: September 2001
  • Laatst online: 11-03-2022
Rexomnium schreef op dinsdag 20 december 2005 @ 16:15:
...dat is inderdaad een mogelijke oplossing, maar hoe zit het dan als een jaar 53 weken heeft?
Dan doe je if weeknummer >= 52 ? Dat had je best zelf kunnen bedenken, toch?

Acties:
  • 0 Henk 'm!

  • BBrunekreeft
  • Registratie: Mei 2004
  • Laatst online: 08:29

BBrunekreeft

Dus...

Heb je al naar de PEAR:Calendar packages gekeken?
Daarin zitten talloze voorbeelden van kalendertjes en datum/tijd manipulaties.
Gebruik hem zelf ook. Erg handing.

Acties:
  • 0 Henk 'm!

  • Rexomnium
  • Registratie: September 2000
  • Laatst online: 17-09 16:07

Rexomnium

Vincam aut moriar

Topicstarter
Okay het is gelukt met de oplossing van Chris. Als het week nummer gelijk of groter is dan 52, dan doe ik voor de begindatum jaar-1, is het weeknummer gelijk is aan 1, dan doe ik voor de einddatum het jaar+1.
BBrunekreeft schreef op dinsdag 20 december 2005 @ 16:19:
Heb je al naar de PEAR:Calendar packages gekeken?
Daarin zitten talloze voorbeelden van kalendertjes en datum/tijd manipulaties.
Gebruik hem zelf ook. Erg handing.
Thx, maar ik ben een beginner op programmeergebied en ik wilde het graag helemaal zelf doen. Code overnemen is niet moeilijk, maar het idee erachter snappen wel :)

[ Voor 55% gewijzigd door Rexomnium op 20-12-2005 16:37 ]

We zijn allemaal vaandeldrager in een optocht van gekwetsten.


Acties:
  • 0 Henk 'm!

Verwijderd

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// create date("N") manually because current PHP version here is not 5.1.0+.
// If your version is 5.1.0+, then you can replace the `dateN`-function calls
// in the `fullWeeksOfMonth`-function with a call to date("N", yourtimestamp).
function dateN($timestamp) {
    $w = date("w", $timestamp);
    $convert = array(0=>7,1=>1,2=>2,3=>3,4=>4,5=>5,6=>6);
    return $convert[$w];
}

function monthStampsRoundedOnWeeks($curmonth, $curyear) {

    // init last day number of month
    $lastdaynumber = date("t", mktime(0,0,0,$curmonth,1,$curyear));
    
    // init start- and enddate of current month as timestamps
    $firstday = mktime(0,0,0,$curmonth,1,$curyear);
    $lastday = mktime(0,0,0,$curmonth,$lastdaynumber,$curyear);

    // Put every timestamp, per day of the month, in an array.
    $days = array();
    for($i=1;$i<=$lastdaynumber;$i++) {
        $days[] = mktime(0,0,0,$curmonth,$i,$curyear);
    }

    // We want the view to start with a monday.
    // We check or we have to add some timestamps
    // (of the previous month) in front of the 
    // timestamps in the `$days`-array. We preform this
    // by checking the daynumber of the startdate. If that
    // number is bigger then one (= not monday but later that week)
    // we add timestamps to the `$previous`-array.
    $infront = array();
    $loopdate = $firstday;
    $loopkey = dateN($firstday);
    for($i=$loopkey;$i>1;$i--) {
        $loopdate -= 60*60*24;
        $loopkey--;
        $infront[$loopkey] = $loopdate;
    }
    ksort($infront);

    // See above, but this time for end of the month.
    // We want the view to end with a sunday.
    $inback = array();
    $loopdate = $lastday;
    for($i=dateN($lastday);$i<7;$i++) {
        $loopdate += 60*60*24;
        $inback[] = $loopdate;
    }

    // combine the three collected arrays
    // to one array that contains all the timestamps.
    $days = array_merge($infront, $days, $inback);

    // result
    return $days;

}

// test the function
$test = monthStampsRoundedOnWeeks(12, 2005);
foreach($test AS $timestamp) {
    echo date("l d-m-Y", $timestamp).'<br>';
}

Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 16:36
Verwijderd schreef op dinsdag 20 december 2005 @ 17:22:
PHP:
1
2
3
4
//[..]
    $loopdate -= 60*60*24;
//[..]
}
Dat is een redelijk lijpe manier om door dagen te loopen. Dankzij daylight saving zijn er namelijk ook dagen die 25 respectievelijk 23 uur duren. Ergens eind oktober krijg je met deze constructie dus 2 dagen met dezelfde datum. In het voorjaar sla je die dag weer over als je met +=60*60*24 door dagen heenloopt. De "correcte" manier om over dagen te itereren is:
PHP:
1
strtotime('+1 day', $timestamp);

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

Verwijderd

T-MOB schreef op dinsdag 20 december 2005 @ 19:50:
[...]

Dat is een redelijk lijpe manier om door dagen te loopen. Dankzij daylight saving zijn er namelijk ook dagen die 25 respectievelijk 23 uur duren. Ergens eind oktober krijg je met deze constructie dus 2 dagen met dezelfde datum. In het voorjaar sla je die dag weer over als je met +=60*60*24 door dagen heenloopt. De "correcte" manier om over dagen te itereren is:
PHP:
1
strtotime('+1 day', $timestamp);
Met je eens. Heb de code erg snel en ongecheckt getypt en dat zijn inderdaad foutjes die de TS er zelf lekker uit mag halen en verbeteren :Y) Wat ik net, tijdens een bord overheerlijke nasi overigens, bedacht was trouwens een andere - volgens mij betere en snellere - methode.

Gedachte;
Begint de week van de startdatum met een maandag? Zo nee, de week daarvoor meenemen in het verhaal (er van uitgaand dat de weeknummers van een start op maandag uitgaan). Aan het einde van de maand idem, eindigt de week op een zondag? Zo nee, de week daarná ook nog meenemen in het verhaal. Met de dan geselecteerde weken kun je vervolgens doen wat je wilt en dit is een snellere methode dan mijn code van vanmiddag.

Succes.

Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 16:36
Verwijderd schreef op dinsdag 20 december 2005 @ 21:51:
Met je eens. Heb de code erg snel en ongecheckt getypt en dat zijn inderdaad foutjes die de TS er zelf lekker uit mag halen en verbeteren :Y)
't Was niet de bedoeling om je op de methode aan te vallen. Het viel me gewoon op dat veel mensen uitgaan van "een dag is 24uur dus 3600*24 seconden". Punt is dat ons tijdsysteem allerlei rariteiten kent (zomertijd, schrikkeljaren) die niet zo maar in wat simpele rekensommetjes zijn op te lossen. Noem het "derde dinsdag in september"-problematiek: het klinkt logisch maar schrijf er maar een algorithme voor.
Gedachte;
Begint de week van de startdatum met een maandag? Zo nee, de week daarvoor meenemen in het verhaal (er van uitgaand dat de weeknummers van een start op maandag uitgaan). Aan het einde van de maand idem, eindigt de week op een zondag? Zo nee, de week daarná ook nog meenemen in het verhaal. Met de dan geselecteerde weken kun je vervolgens doen wat je wilt en dit is een snellere methode dan mijn code van vanmiddag.
Je gaat er van uit dat de TS de weken wil volmaken met de dagen uit de vorige en volgende maand. Ik denk dat hij/zij dat niet behoeft. En dan volstaat het volgende:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function minical ($year, $month) {

    //get days in the month
    for ($day=1; checkdate($month, $day, $year); $day++) {
        $stamp = mktime(0,0,0,$month, $day, $year);

        $weekno = date("W", $stamp);
        $dayofweek = date("w", $stamp);
        $dayofweek = ($dayofweek == 0) ? 7 : $dayofweek;

        $weeks[$weekno][$dayofweek] = $day;
    }


    //start the output table
    $output =    '<table class="minical">' ."\n"
                .' <thead>' ."\n"
                .'  <tr><th class="month" colspan="8">' .date("F Y", mktime(0,0,0,$month,1, $year)) .'</th></tr>' ."\n"
                .'  <tr><th class="week">Wk</th><th>Mo</th><th>Tu</th><th>We</th><th>Th</th><th>Fr</th><th>Sa</th><th>Su</th></tr>'
                ."\n" .' </thead>' ."\n" .' <tbody>' ."\n";


    //loop trough weeks for output
    foreach ($weeks as $weekno => $data) {
        $output .= '  <tr><th class="week">' .$weekno .'</th>';
        for ($i=1; $i<=7; $i++) {
            if (!isset($data[$i])) { $data[$i] = ''; }

            $class = ($i >= 6) ? ' class="weekend"' : '';
            $output .= '<td' .$class .'>'.$data[$i] .'</td>';
        }

        $output .= '</tr>' ."\n";
    }

    //table end
    $output .= ' </tbody>' ."\n" .'</table>' ."\n";

    return $output;
}

Regeren is vooruitschuiven

Pagina: 1