Eerste woensdag van de huidige maand en de 5 volgende maanden

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Bart Lambert

Bart Lambert

20/10/2012 16:55:11
Quote Anchor link
Hallo iedereen,

In het maken van PHP-scripts ben ik een leek en probeer aldoende bij te leren. Voor onze sportvereniging onderhoud ik een website met daarop onderandere een agenda. Het eerste item op deze agenda is een maandelijkse bijeenkomst, telkens op de eerste woensdag van de maand, ongeacht of dit een feestdag is.

De originele Agenda is een html-pagina waar ik dan eenmaal per maand de data verander.

Daar er aan de website een database gekoppeld is, heb ik van deze pagina een PHP-paginaPHP-pagina gemaakt waar ik succesvol een script heb ingebracht (via een include()) om de namen te tonen van de leden die in de huidige maand verjaren.

Nu wou ik een tweede script toevoegen waarin de eerste woensdag van de huidige maand en de eerste woensdag van de volgende 5 maanden wordt weergegeven. Dat script is klaar en werkt naar behoren!

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
    
//lus om opeenvolgende maanden te bepalen

for ($i==0;$i<6;$i++){
    
// Voor de huidige maand, splits in 3 factoren
    
    if($i==0)
        {
            
            $haaldatum = date('d-m-Y');
        $splitsdatum[$i] = explode('-',$haaldatum);



//$num bepaald op welke dag de eerste van de maand valt            

$num = date("w",mktime(0,0,0,$splitsdatum[$i][1],1,$splitsdatum[$i][2]));

// als de eerste van de maan een woensdag is, echo datum
    if($num==3){
        echo date("j F Y",mktime(0,0,0,$splitsdatum[$i][1],1,$splitsdatum[$i][2]))."<br/>";
        
// is de eerste van de maand geen woensdag maar groter, bereken de eerste woensdag vanaf 3de van de maand
    }elseif($num>3){
        echo date("j F Y",mktime(0,0,0,$splitsdatum[$i][1],3,$splitsdatum[$i][2])+(86400*(8-$num)))."<br/>";
        
//    is de eerste van de maand geen woensdag maar kleiner, bereken de eerste woensdag voor de 3de van de maand    
    }else{
        echo date("j F Y",mktime(0,0,0,$splitsdatum[$i][1],3,$splitsdatum[$i][2])+(86400*(1-$num)))."<br/>";
    }

// haal datum op voor de *i-de volgende maannd
        }else{
            $haaldatum = date('d-m-Y',strtotime('+'.$i.' months'));
            $splitsdatum[$i] = explode('-',$haaldatum);
            
            $num = date("w",mktime(0,0,0,$splitsdatum[$i][1],1,$splitsdatum[$i][2]));
// als de eerste van de maan een woensdag is, echo datum
    if($num==3){
        echo date("j F Y",mktime(0,0,0,$splitsdatum[$i][1],1,$splitsdatum[$i][2]))."<br/>";
// is de eerste van de maand geen woensdag maar groter, bereken de eerste woensdag vanaf 3de van de maand        
    }elseif($num>3){
        echo date("j F Y",mktime(0,0,0,$splitsdatum[$i][1],3,$splitsdatum[$i][2])+(86400*(8-$num)))."<br/>";
//    is de eerste van de maand geen woensdag maar kleiner, bereken de eerste woensdag voor de 3de van de maand    
    }else{
        echo date("j F Y",mktime(0,0,0,$splitsdatum[$i][1],3,$splitsdatum[$i][2])+(86400*(1-$num)))."<br/>";

        }
    
}
}

    ?>


Als resultaat krijg ik dus telkens de datum van de eerste woensdag voor de huidige en 5 volgende maanden.

Als ik dit script nu kopieer en plak op de pagina agenda2.php krijg ik de echo's niet te zien.

Agenda bestaat uit een tabel en de code heb al op verschillende manieren ingevoerd (Copy/paste, include ()...

Ik krijg ook geen foutmelding en de pagina wordt gewoon opgebouwd.

Iemand enig idee waar dit fout gaat?
 
PHP hulp

PHP hulp

29/04/2024 09:13:24
 
Frank Nietbelangrijk

Frank Nietbelangrijk

20/10/2012 17:23:08
Quote Anchor link
In ieder geval is dit een hele mooie spaghetti-brei. Veel if/else lussen maken de code compleet onleesbaar en dus ook onbeheersbaar Kijk eens naar functies

Toevoeging op 20/10/2012 18:18:51:

Dus zo zou het ook kunnen,

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

function getNextWeekday($timestamp, $wday, $weeks) {
    $date = getdate($timestamp);    // vraag info op van deze timestamp
    $days = $wday - $date['wday'];  // gevraagde weekdag - dag vd week van timestamp
    if($days < 0)
        $days += 7;
    $timestamp += 60 * 60 * 24 * $days; // sec * min * uur * dagen
    $timestamp += $weeks * 60 * 60 * 24 * 7; // $weeks vooruit
    return $timestamp;
}


$timestamp = mktime();

for($weeks = 0 ; $weeks < 5 ; $weeks++) {
    $wednesday = getNextWeekday($timestamp, 3, $weeks);
    echo ($weeks + 1).'e woensdag: '.date('d-m-Y', $wednesday).'<br>';
}


?>
Gewijzigd op 20/10/2012 18:31:55 door Frank Nietbelangrijk
 
Bart Lambert

Bart Lambert

20/10/2012 18:53:44
Quote Anchor link
hallo, daar ik nog niet zo bedreven ben in php zal ik nog wat moeten werken aan de functie scripts. het opgegeven script is echter het probleem niet, dat werkt prima. het is enkel is ik een nieuwe pagina maak en daarin met include (), dan krijg ik de resultaten niet te zien.

Toevoeging op 20/10/2012 18:54:49:
Gewijzigd op 20/10/2012 19:05:32 door Bart Lambert
 
Frank Nietbelangrijk

Frank Nietbelangrijk

20/10/2012 18:59:48
Quote Anchor link
Natuurlijk Bart, leren kost tijd. Maar probeer het toch maar vanaf het begin: functies schrijven die een bepaalde taak uitvoeren. Het zijn feitelijk kleine prog-jes die je altijd weer kunt herbruiken. In het begin is het misschien wat moeizaam maar later ga je er o zo blij mee zijn.

enne welkom hoor ook van mij
 
Bart Lambert

Bart Lambert

20/10/2012 19:08:29
Quote Anchor link
Ben een klein stukje verder:

De pagina waar het script wordt toegevoegd met include(), bevat reeds een include(). als ik nu die ene wegdoen, dan verschijnt de andere wel. Kan een pagina maar 1 include () bevatten?
 
Frank Nietbelangrijk

Frank Nietbelangrijk

20/10/2012 19:17:40
Quote Anchor link
Nee. een pagina kan vele includes bevatten.
Ik ben persoonlijk geen voorstander van includes op de gekste plekken midden in de code. Ik zou deze zoveel mogelijk bovenin de pagina die door de server opgevraagd wordt houden. in combinatie met de eerder besproken functies werkt dat prima.

Toevoeging op 20/10/2012 19:21:06:

datum.php:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
function getNextWeekday($timestamp, $wday, $weeks) {
    $date = getdate($timestamp);    // vraag info op van deze timestamp
    $days = $wday - $date['wday'];  // gevraagde weekdag - dag vd week van timestamp
    if($days < 0)
        $days += 7;
    $timestamp += 60 * 60 * 24 * $days; // sec * min * uur * dagen
    $timestamp += $weeks * 60 * 60 * 24 * 7; // $weeks vooruit
    return $timestamp;
}

?>


index.php:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
include_once('datum.php');

$timestamp = mktime();

for($weeks = 0 ; $weeks < 5 ; $weeks++) {
    $wednesday = getNextWeekday($timestamp, 3, $weeks);
    echo ($weeks + 1).'e woensdag: '.date('d-m-Y', $wednesday).'<br>';
}


?>
Gewijzigd op 20/10/2012 19:21:39 door Frank Nietbelangrijk
 
Bart Lambert

Bart Lambert

20/10/2012 19:24:16
Quote Anchor link
nu denk ik het gevonden te hebben, beide scripts hadden een $i die voor verschillende doeleinden gebruikt werd. Door in een script de $i te vervangen door de niet gebruikte $j komt het script opeens wel tevoorschijn!

hoera voor mezelf! dit draadje mag voor mij part gesloten worden, probleem opgelost.

Volgende stap is de script uiteen trekken in functies!


Toevoeging op 20/10/2012 19:32:58:

hey frank, heb jouw scripts eens bekeken. Als ik het goed begrijp, bereken jij hier alle data van de vijf opeenvolgende woensdagen? Als ik het niet goed begrijp... dan heb ik nog veel te leren!!! ;-)

Ik wil enkel de eerste woensdag van de maand.

groeten, bart
 
Frank Nietbelangrijk

Frank Nietbelangrijk

20/10/2012 19:36:38
Quote Anchor link
Klopt, en proficiat, toch nog even zeuren:

Als je functies had gebruikt had je geen last gehad van een dubbele $i of $j.

groet,
Frank
 
Eddy E

Eddy E

20/10/2012 19:50:54
Quote Anchor link
http://www.webmastercity.nl/forum/viewtopic.php?f=35&t=38059

En dan query:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
SELECT datum, DAYNAME( datum )
FROM alle_data
WHERE datum > NOW( )
AND DAYOFWEEK( datum ) =4
AND DAYOFMONTH( datum ) BETWEEN 1 AND 8  
ORDER BY datum ASC
LIMIT 0, 5


Dit geeft (even via mijn database gedaan):

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
datum       DAYNAME( datum )
2012-11-07    Wednesday
2012-12-05    Wednesday
2013-01-02    Wednesday
2013-02-06    Wednesday
2013-03-06    Wednesday


Let op dat het YYYY-MM-DD-formaat is ;).
En geen gezeur met halve weken, GROUP BY etc.
Qua snelheid....: Weergave van records 0 - 4 ( 5 totaal, query duurde 0.0008 sec) [datum: 2012-11-07 - 2013-03-06]

Tevens werkt de mijne ook bij schrikkeldagen/jaren als de dag geen 24*60*60 seconden telt.
Enig nadeel (wat heel simpel te verhelpen is): hij gaat maar tot 2100.
Gewijzigd op 20/10/2012 20:04:02 door Eddy E
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

20/10/2012 22:47:32
Quote Anchor link
Eddy, om te beginnen:
Ik haal 3 fouten uit jouw query, nl:
Quote:
WHERE datum > NOW()

Wat als NOW de eerste woensdag (euh donderdag) van de maand is?
Quote:
AND DAYOFWEEK( datum ) =4

is een donderdag
Quote:
AND DAYOFMONTH( datum ) BETWEEN 1 AND 8

als jouw donderdag op de eerste valt heb je 2 donderdagen
Maar dat je dit op een forum durft te zetten:
Quote:
Alle werkdagen van een jaar/maand
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
    SELECT datum, DAYNAME(datum)
    FROM alle_data
    WHERE YEAR( datum ) = '2009'
    AND MONTH( datum ) = '3'
    AND DAYOFWEEK( datum ) BETWEEN 2 AND 6
    ORDER BY datum ASC

In Nederland werken we van maandag t/m vrijdag

Maar dan veel belangrijker:
Een database is bedoeld om om dynamische gegevens op te slaan, een kalender 1971 tot 2037 (het bereik van da normale datetime funcies in PHP) is niet dynamisch maar ligt vast
Gewijzigd op 20/10/2012 22:51:19 door Ger van Steenderen
 
Eddy E

Eddy E

20/10/2012 23:17:59
Quote Anchor link
Daar hebben we het vaker over gehad Ger. Ik geef gewoon een simpelere en flexibelere manier.
SQL begint op zondag en dus is 4 woensdag. Zondag is volgens diverse systemen ook de eerste dag. Zeker in de Gregoriaanse kalender. Daarnaast zie je de resultaten... 4 = Wednesday...

Tenzij je dit script op woensdag 1 xxx om 23:69:59,999999 aanroept is er niets aan de hand.
 
Frank Nietbelangrijk

Frank Nietbelangrijk

20/10/2012 23:57:01
Quote Anchor link
Ger en Eddy database masters zijn jullie :)
 
Eddy E

Eddy E

21/10/2012 11:53:19
Quote Anchor link
Nou, Ger heeft er veel meer kaas van gegeten dan ik hoor.
Echter, ben ik van mening dat in een database niet alleen dynamische gegevens staan, maar gewoon 'gegevens'.
En een datum is ook een gegeven iets.

Als ik de query iets optimaliseer krijg ik dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
SELECT datum, DAYNAME(datum)
FROM alle_data
WHERE datum >= NOW()
AND DAYOFWEEK(datum) = 4
AND DAYOFMONTH(datum) BETWEEN 1 AND 7  
ORDER BY datum ASC
LIMIT 5


Mocht op jouw systeem de donderdag verschijnen, verander dan de 4 naar een 3.
 
Frank Nietbelangrijk

Frank Nietbelangrijk

21/10/2012 11:57:07
Quote Anchor link
Ik zou er nooit aan gedacht hebben en los het zo op in php, maar dit kan natuurlijk ook en ik vind t knap :)
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

21/10/2012 12:57:05
Quote Anchor link
Eddy,
De wortel van 666 is ook een gegegeven, maar je gaat toch geen tabel maken voor de uitkomsten van de wortel van 1 tot en met weet ik veel wat. Dit is logica die in de applicatie laag thuis hoort, zo ook voor een datum.

Overigens heb je gelijk met de dag van de week, ik was even in de war met PHP.

datum >= NOW() gaat nog steeds niet goed, al datum vandaag is wordt dit
2012-10-21 00:00:00 >= 2012-10-21 12:56:04
omdat je een datum met een datum tijd vergelijkt.

Toevoeging op 21/10/2012 14:21:11:

De PHP oplossing:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
//$dayofweek 1 voor ma 7 voor zondag
function getAFirstDayOfMonths($dayofweek = 3, $range = 5, $dateformat = '%d-%m-%Y') {
    $date = time();
    $wd = date('N', $date);
    //bepaal de eerste ?dag van de week
    $someday = $date + (($dayofweek - $wd) * 86400);
    //corrigeer als er een maand terug gegaan wordt
    $someday += (date('m', $date) != date('m', $someday)) ? 7 * 86400: 0;
    $dom = date('j', $someday);
    //als de dag van de maand groter is dan 7 moeten we er een x aantal weken aftrekken
    //en een coorectie uitvoeren op veelvouden van 7

    $firstday = ($dom > 7) ? $someday - ((($dom % 7 == 0) ? -1 : 0) + floor($dom / 7)) * 7 * 86400 : $someday;
    $maand = date('m', $firstday);
    $firstdayS = array(strftime($dateformat, $firstday));
    for ($i=1; $i<=$range;$i++) {
        $dom = date('j', $firstday);
        $year = date('Y');
        //bepaal de laatse dag van de maand
        if ($maand <= 7) {
            //t/m juli hebben de oneven maanden 31 dagen
            if($maand % 2 > 0) {
                $ldom = 31;
            }

            else {
                if($maand != 2) { //behalve feb
                    $ldom = 30;
                }

                else { //feb 28 behalve schrikkeljaren
                    $ldom = ($year % 4 != 0 || ($year % 100 == 0 && $year % 400 != 0)) ? 28 : 29;
                }
            }
        }

        else { //na juli de even maamden 31
            $ldom  = ($maand % 2 == 0) ? 31 : 30;
        }

        $weeks2add = ($ldom - $dom - 28 < 0) ? 4 : 5;
        $firstday += $weeks2add * 7 * 86400;
        $firstdayS[] = strftime($dateformat, $firstday);
        $maand = date('m', $firstday);
    }

    return $firstdayS;
}

?>
Gewijzigd op 21/10/2012 14:27:05 door Ger van Steenderen
 
Eddy E

Eddy E

21/10/2012 14:29:29
Quote Anchor link
Werkt inderdaad ook!
Of het sneller is kan niet zo 1-2-3 zien, wel dat het een stukje geavanceerder is.
En wat een gedoe met het aantal dagen van de maand. Dat is toch ook vaststaand en niet zo ingewikkeld als regel 20 tm 37?
Wellicht een array met 30, 28, 30, 31, 30, 31, 30, 31, 31, 30, 31 beter?
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

21/10/2012 15:00:19
Quote Anchor link
Hi Eddy,
Als er geen schrikkeljaren bestaan had ik het misschien wel in een array gezet, maar ik ben sowieso niet van de hardcoding.
Ik heb even een test gedaan:
de functie: 0.00044798851013184
connect (lokale!)database en select database (nog geen query uitgevoerd!):0.013045072555542
een paar keer getest maar de functie blijft altijd sneller.

En een beetje zelfkritiek kan ook geen kwaad:
Waarom in hemelsnaam rekening houdem met eeuwen terwijl over 25 jaar deze functie niet meer zal werken


Toevoeging op 21/10/2012 15:10:28:

Speciaal voor jou:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT
    CASE DAYOFWEEK(datum)
        WHEN 2 THEN 'Maandag'
        WHEN 3 THEN 'Dinsdag'
        WHEN 4 THEN 'Woensdag'
        WHEN 5 THEN 'Donderdag'
        WHEN 6 THEN 'Vrijdag'
        WHEN 7 THEN 'Zaterdag'
        ELSE 'Zondag'
    END AS dagnaam
FROM
    all_data
WHERE
    datum >= CURRENT_DATE();
LIMIT 7
 
Frank Nietbelangrijk

Frank Nietbelangrijk

21/10/2012 17:25:15
Quote Anchor link
Ger van Steenderen op 21/10/2012 15:00:19:
Hi Eddy,
Als er geen schrikkeljaren bestaan had ik het misschien wel in een array gezet, maar ik ben sowieso niet van de hardcoding.

Is ook niet zo moeilijk:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

function isLeap($year) {
    if($year % 400 == 0)
       return true;
    else if($year % 100 == 0)
       return false;
    else if($year % 4 == 0)
       return true;
    return false;
}


?>


Groet, Frank

Toevoeging op 21/10/2012 17:26:16:

Wel grappig om te zien dat we allemaal een andere oplossing hebben voor hetzelfde probleem
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

21/10/2012 17:41:41
Quote Anchor link
Ik heb ook niet gezegd dat het moeilijk is:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
$ldom = ($year % 4 != 0 || ($year % 100 == 0 && $year % 400 != 0)) ? 28 : 29;

Maar goed, zoals het nu voorstaat in PHP, haalt de functie jaar 2038 niet eens dus laat staan jaar 2100 (wat ik ik ook niet zal halen, dus boeien). En ik gebruik bewust geen datetime objecten omdat die geen locales ondersteunen.
 
Eddy E

Eddy E

21/10/2012 18:59:05
Quote Anchor link
Je functie is dan inderdaad een stuk sneller. En dus de moeite om te bewaren.
En helemaal met je eens: in 2025 zullen deze scripts ook niet meer nodig zijn, want dan is er wel iets beters/makkelijkers/handigers voor gevonden.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.