Zeitsteuerung mit php

  • Hallo,


    ich habe auf dem Pi einen Webserver mit einem php Skript.
    Ein Arduino ruft regelmäßig auf dem Pi eine bestimmte Seite auf und erhält dabei als Seiteninhalt "an" oder "aus" und schaltet entsprechend.


    Im php-Skript kann man einstellen in welchem Zeitraum z.B. 10:05-16:15 Uhr eingeschaltet bzw. ausgeschaltet werden soll.


    Bei Aufruf der Seite muss ich nun abfragen, ob sich die aktuelle Zeit zwischen der Anfangs und Endzeit befindet.


    Dazu habe ich bereits die Abfrage in 2 Bereiche unterteilt:
    1. Anfangszeit kleiner Endzeit
    2. Anfangszeit größer Endzeit (über 0 Uhr)


    Bei 1 habe ich folgende Abfrage:
    (Stundeanfang < Stundeaktuell) oder (( Stundeanfang = Stundeaktuell) und (Minuteanfang < Minuteaktuell))


    und


    (Stundeende > Stundeaktuell) oder (( Stundeende = Stundeaktuell) und (Minuteende > Minuteaktuell))


    Aber wie erstelle ich die Abfrage bei 2, wenn es über 24 Stunden geht ...


    Vielen Dank
    itsy

  • Hi,


    bei den gefühlten 40°C im Wohnzimmer ist mir dein Zerlegen in Stunden und Minuten gerade ein wenig zu herausfordernd, deshalb schlage ich dir hier eine alternative Lösung vor:




    Diese Lösung arbeit mit Unix-Timestamps. Diese sind besonders einfach zu vergleichen, weil es einfach Integers sind. Die Funktion strtotime kann ein wahrer Segen sein, da sie viele Formate in einen Unix-Timestamp umwandelt. Als einfaches Beispiel liefert dir strtotime('now') den aktuellen Timestamp (genau so wie time() es macht). strtotime('tomorrow') liefert dir den Timestamp für den nächsten Tag um 00:00. Hier nutze ich aber als Parameter nur eine der beiden Zeitangaben.


    $start = strtotime('10:00');


    Liefert dann z.B. den Timestamp für den aktuellen Tag um 10:00.


    Was jetzt vielleicht noch ein bisschen ungewöhnlich ist, ist der Vergleich zweier Zeichenketten


    if ($startzeit > $endzeit) { ... }


    Da beides Zeichenketten sind wendet PHP hier einen lexikalischen Vergleich an. Deshalb ist die führende Null bei 01:00 auch wichtig. So kann man leicht herausfinden, ob die Endzeit VOR der Startzeit liegt, und somit in den nächsten Tag hineinreicht.


    Lange Rede...


    Für die Startzeit nehmen wir immer den aktuellen Tag an.
    Wenn der Start NACH dem Ende liegt, erzeugen wir einen Timestamp für den nächsten Tag mit der gewünschten Uhrzeit ( strtotime('tomorrow 01:00') ). Falls das nicht der Fall ist, nehmen wir ebenfalls heute an. Zu guter letzt testen wir nur noch, ob JETZT zwischen START und ENDE liegt und sind fertig.

  • Du kannst auch mit der neueren DateTime klasse arbeiten, das ist finde ich übersichtlicher und etwas schneller ist es auch.


    Code
    $jetzt = new DateTime('now');
    $start = new DateTime('2013-07-23 15:00:00');
    $ende  = new DateTime('2013-07-24 10:00:00');
    if($start >= $jetzt && $jetzt <= $ende) {
       echo 'an';
    } else {
       echo 'aus';
    }


    Die DateTime Objekte kann man einfach vergleichen und man kann auch mit Daten jenseits von 1970 und 2069 arbeiten. Auch über Tage oder noch längere Zeiträume hinweg lässt sich so kinderleicht rechnen und vergleichen.

  • Hatte irgendwie im Kopf, dass sowas wie new DateTime("tomorrow") nicht funktioniert. Tut es aber doch :) Meiner Meinung nach sollte man, wie agent47 vorgeschlagen hat, die Klassen bevorzugen. DateTime Objekte sind bei etwas aufwändigeren Dingen deutlich handlicher als Int-Timestamps.

  • warum nicht über NTP ?


    ist doch eine Zahl die kontinuierlich wächst, also das/die Schalt Datum/Zeit in NTP umrechnen und mit NTP vergleichen ?

    lasst die PIs am Leben !
    Energiesparen:
    Das Gehirn kann in Standby gehen. Abschalten spart aber noch mehr Energie, was immer mehr nutzen. Dieter Nuhr
    (ich kann leider nicht schneller fahren, vor mir fährt ein GTi)



  • Moin,


    ich programmiere zwar fast ausschliesslich in "C", ab und zu auch mal was anderes, aber ich bevorzuge ebenfalls die Timestamps.
    Aus meiner Sicht bist Du immer auf der sicheren seite, brauchst Dich um Schaltjahre und Sommerzeit nicht kümmern und kannst ganz einfach rechnen.


    Das sind zwar jetzt keine "integer", wie hacksteak schrieb, sondern können von System zu System verschieden sein, aber zum rechnen kann man sie watschneinfach verwenden - da stimme ich ihm vollkommen zu.


    jar: was meinst Du mit NTP? Ich kenne nur das "network time protocol" :s


    cu,
    -ds-


  • jar: was meinst Du mit NTP? Ich kenne nur das "network time protocol" :s
    cu,
    -ds-



    stimmt, ist wohl eine 64-bit Zahl die kontinuierlich wächst was Zeitvergleiche erleichert


    2x 32 bit, etwas Schieberei und fertig ist das NTP Format und dann vergleicht man


    an meinem Webserver hole ich mir die NTP und berechne MEZ oder MESZ
    an meinem Timer habe ich das mit DCF77 Protokoll gemacht, eben in 59-bit




    Aus meiner Sicht bist Du immer auf der sicheren seite, brauchst Dich um Schaltjahre und Sommerzeit nicht kümmern und kannst ganz einfach rechnen.
    cu,
    -ds-


    na ja, man muss schon wissen das 10:00 Uhr im Sommer MESZ was anderes meint als im Winter MEZ im NTP gibt es ja "nur" GTM

    lasst die PIs am Leben !
    Energiesparen:
    Das Gehirn kann in Standby gehen. Abschalten spart aber noch mehr Energie, was immer mehr nutzen. Dieter Nuhr
    (ich kann leider nicht schneller fahren, vor mir fährt ein GTi)

    Edited once, last by jar ().


  • stimmt, ist wohl eine 64-bit Zahl die kontinuierlich wächst was Zeitvergleiche erleichert
    ...



    na ja, man muss schon wissen das 10:00 Uhr im Sommer MESZ was anderes meint als im Winter MEZ im NTP gibt es ja "nur" GTM


    Hi jar,


    Deine 64-Bit Zahl ist imho nichts anderes als eine Unix-Timestamp (ist, wie gesagt, nicht genormt besteht aber oft aus 8 Byte - müsste man in den RFCs nachlesen was das ist bei NTP).
    Und was die Sommer-/Winterzeit bzw. Schaltjahre betrifft: das musst Du eben nicht wissen, weil Du mit localtime den Timestamp gleich passen für Deine Zeitzone umwandeln kannst, nachdem Du z.B. 17*24*60*60 (für z.B. 17 tage) drauf addiert hast. Da brauchst Du Dich auch nicht mehr um den 29.2. kümmern ;) ...


    cu,
    -ds-

  • Zum Glück stellt PHP sicher, dass time() und ähnliche Funktionen immer mit Integers arbeiten (oder irre ich mich da? Das Manual ist ja nicht immer eindeutig). Wieviel Byte das dann sind, ist wieder was anderes.


    Bezüglich Zeitzonen, Sommerzeit usw. musste ich vor laaaanger Zeit feststellen, dass ein Tag eben nur im Durchschnitt 24 Stunden hat. Seit dem sehe ich Datum und Zeit aus einer anderen Perspektive :)


    Wie aber schon vorher gesagt bevorzuge ich in PHP eigentlich DateTime. Zusamen mit DatePeriod, DateIntervall usw. hat man hier eine Möglichkeiten mit einer halbwegs netten API.

  • Die DateTime API kann wesentlich besser mit Zeiten umgehen als es mit Timstamps geht, nicht nur das es übersichtlicher ist, auch das addieren und subtrahieren, sowie das vergleichen und das Arbeiten mit Zeitzonen und Sommer/Winterzeit ist schnell und übersichtlich, mit Timestamps muss man da gerade drauf achten.


    Beispiel:

    Code
    $time = time();
    $time += 86400;
    echo format('r', $time);


    Hier muss man erst schauen und überlegen was der Code genau macht, das gleiche mit DateTime:

    Code
    $time = new DateTime('now');
    $time->add('P1D');
    echo $time->format('r');


    Das ist ja noch relativ Simultan, aber sobald es um Zeitzonen geht wird es schwiriger:


    Code
    $time = time();
    $time += 86400 - 3600;
    echo format('r', $time);


    Code
    $time = new DateTime('now', new DateTimeZone('Europe/London');
    $time->add('P1D');
    echo $time->format('r');


    Das neue PCC welches bald fertig ist setzt auch schon voll auf DateTime inklusive ein paar eigenen zusätzlichen compfort funktionen.

  • Vielen Dank für die vielen Antworten :-)


    Das Beispiel von hacksteak werde ich gleich mal testen - das ist für mich nachvollziehbar und passt Du meiner Datenbank.


    Das DateTime-Beispiel muss ich dagegen erst "tomorrow" manuell "berechnen", damit es wie eine 24Stunden-Analog-Zeitschaltuhr funktioniert. So habe ich das zumindest verstanden.


    Werde das gleich mal testen :-)

  • Sodele, hab jetzt mal mit dem ersten Beispiel angefangen (sah für ich einfacher aus ;-) ).


    Beim Test habe ich folgendes Problem festgestellt:
    Einschalten von 23 Uhr bis 20 Uhr. Demnach sollte er nun den Zustand "ein" haben (soll ja wie eine normale analoge Zeitschaltuhr funktionieren).
    ABER nach Prüfung der Umrechnungen nimmt der die 23 Uhr von HEUTE. Demnach ich now<start ... :-/

    Edited once, last by itsy ().

  • Ich habe mir jetzt mal folgendes überlegt. Kann mir jemand sagen, ob ich richtig gedacht habe?


    if (($startzeit < $endzeit) AND (strtotime($startzeit) < $now)) {
    $start = strtotime($startzeit);
    $end = strtotime($endzeit);
    };

    if (($startzeit > $endzeit) AND (strtotime($startzeit) < $now)) {
    $start = strtotime($startzeit);
    $end = strtotime('tomorrow' . $endzeit);
    };

    if (($startzeit > $endzeit) AND (strtotime($startzeit) > $now)) {
    $start = strtotime('yesterday' . $startzeit);
    $end = strtotime($endzeit);
    };

  • Ok... Das mit in-Timestamps umwandeln ist auch doof ^^


    Nächster Versuch, auf Basis von String-Vergleichen... Folgender Denk-Ansatz:


    $t0 = Startzeit
    $t1 = Endzeit
    $now = jetzt


    1. Wenn beide Zeiten am gleichen Tag liegen, also $t0 < $1, reicht eine einfache Prüfung, ob $t0 <= $now && $t1 >= $now.
    2. Wenn zwischen beiden Zeiten ein Tageswechsel liegt, also wenn $t0 > $t1, dann prüfen wir, ob wir außerhalb des Zeitfensters liegen und negieren das Ergebnis, um die gleiche Aussage zu bekommen.


    Folgende Funktion sollte die Antwort liefern:




    Um das ganze zu verifizieren, hier noch ein Test-Szenario. Das Array $zeiten ist dabei ein Array von Test-Werten, wobei folgender Aufbau für die Elemente gilt:


    1. $t0, Startzeit
    2. $t1, Endzeit
    3. simuliertes JETZT
    4. erwartetes Ergebnis


    In der Schleife wird die Funktion für jeden Testfall aufgerufen und entweder OK oder FEHLER ausgegeben.



  • ok, ich muss einen Denkfehler haben, denn es funktioniert nicht :-/
    [hr]
    DU warst schneller - ich meinte mein Posting ... ;-)
    [hr]
    Es funktioniert :-)
    Ich danke Euch allen für Eure Hilfe :-) Ohne EUch hätte ich das nicht geschafft!
    Jetzt werden Relais bestellt, damit ich auch was schalten kann :-)

    Edited once, last by itsy ().