Zeitfenster überprüfen

  • Hallo zusammen,


    das unten aufgeführte Skript soll herausfinden, ob die aktuelle Uhrzeit/Wochentag sich innerhalb des Zeitfensters befindet oder nicht. Funktioniert im Prinzip so lange, bis das Zeitfenster über 24:00:00 Uhr hinaus geht. Dann funktioniert es nicht mehr. Hat jemand einen Lösung oder einen Ansatz für mich, wie ich das Problem beseitigen kann?




    Hier ein Beispiel wann es nicht funktioniert:
    Funktionsaufruf zeitfenster("23:00:00,01:00:00,Mo,Di,Mi,Do,Fr,Sa,So"),
    aktuelle Uhrzeit ist 23:30:00 Uhr, also im Zeitfenster enthalten, es wird aber False zurückgemeldet


    Vielen Dank und sonnige Grüße.


    whitechristmas

  • Hallo whitechrismas,


    Stichwort:

    Code
    Unix Timestamp


    interessiert ein Datumswechsel nicht.


    Beste Grüße


    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - µController-Programmierung in Icon! - ser. Devices - kein Support per PM / Konversation

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Zunächst mal finde ich dein Vorgehen etwas unübersichtlich bzw schwer nachvollziehbar, was aber auch an der Schreibweise des Codes liegt; mal Leerzeichen nach "," manchmal aber nicht usw..


    Auch das was an zeitfenster() übergeben wird ist erst mal nicht nachvollziehbar. So wie es aussieht dienen die ersten 2 Stellen fürs Uhrzeit-Fenster und die restlichen Stellen für die entsprechenden Wochentage? Da würd ich dann lieber 2 unterschiedliche Parameter für nutzen, aber auch die Variablen vernünftig zu benennen.


    Dann wäre es denk ich besser du arbeitest direkt mit datetime Objekten, denn das macht das datetime Modul so besonders. Siehe dazu: https://pymotw.com/3/datetime/#comparing-values


    Wie ich das meine siehst du vielleicht an einem kleinen Beispiel:



    [code=php]
    import datetime


    zeit_format = "%H:%M:%S"


    start_zeit = datetime.datetime.strptime("23:00:00", zeit_format)
    end_zeit = datetime.datetime.strptime("01:00:00", zeit_format)


    print(start_zeit.hour)
    print(end_zeit.hour)


    start_zeit > end_zeit
    start_zeit < end_zeit
    [/php]
    (am besten in die interaktive python Konsole eingeben - einfach nur "python3" ausführen)


    Wichtig wäre allerdings zu prüfen ob end_zeit am nächsten Tag wäre... Also in deinem Problemfall soll das wohl so sein?
    [code=php]
    >>> start_zeit = datetime.datetime.strptime("23:00:00", "%H:%M:%S")
    >>> end_zeit = datetime.datetime.strptime("01:00:00", "%H:%M:%S") + datetime.timedelta(days=1)
    >>> start_zeit
    datetime.datetime(1900, 1, 1, 23, 0)
    >>> end_zeit
    datetime.datetime(1900, 1, 2, 1, 0)
    >>> start_zeit < end_zeit
    True
    >>> start_zeit > end_zeit
    False
    >>>
    [/php]

  • Du vergleichst Zeichenketten miteinander und keine Datetime-Objekte. Zudem wäre auch mit ``weekday()`` es einfacher den Wochentag zu eruieren.
    https://docs.python.org/2/library/datetime.html


    PS: Verzichte auf das ``time`` Modul


    Edit:
    Wie ich sehe, nutzt du ja schon die weekday Methode ;)


    Edit2:
    meigrafd
    ``format`` ist ein reserviertes Wort, besser ``zeit_format`` oder etwas ähnliches.

  • Hallo,


    Quote

    Hier ein Beispiel wann es nicht funktioniert: Funktionsaufruf zeitfenster("23:00:00,01:00:00,Mo,Di,Mi,Do,Fr,Sa,So")


    Das stimmt so nicht. Die Funktion funktioniert schon genau so, wie du die programmiert hast. _Du_ gibst doch `False` zurück, wenn Ende < Start. Was aber nicht das ist, was du _erwartest_.


    Sprich: broken by design :) Wenn das tagesübergreifend funktionieren soll, dann musst du halt davon ausgehen, dass das Enddatum +1 Tag ist, wie von meigrafd gezeigt.


    Und die API von der Funktion `zeitfenster`ist echt gruselig. Wenn man drei Werte erwartest, dann definier' drei Parameter. Einen übergebenen String zu zerlegen, so dass dann "semi-magisch" alles richtig ist, ist schlecht. Und vor allem völlig unpythonisch.


    Besser wäre so was:



    Code
    def zeitfenster(startzeit, endzeit, wochentage=('Mo', 'Di')):
        ....



    oder


    Code
    def zeitfenster (startzeit, endzeit, *wochentage):
        ...


    Gruß, noisefloor

  • Hallo meigrafd,


    woran mache ist fest, ob ich eine Stunde dazurechnen muss oder nicht? Es geht nicht nur darum, ob die Startzeit vor oder nach der Endzeit liegt, sondern ob die aktuelle Uhrzeit (Uhrzeit der Überprüfung) innerhalb des Zeitfensters liegt. Oder hab ich was übersehen? Den Wochentag könnte ich ja wie in meinem Skript überprüfen.


    Wie sieht der Ansatz von Andreas mit timestamp aus? Kann man die Start-/Endzeit und die aktuelle Uhrzeit in Sekunden umrechnen und überprüfen, ob das Zeitfenster erfüllt ist?


    Vielen Dank.


    whitechristmas

  • sollte auch in Python funktionieren strcmp, wenn nicht sollte es mich doch sehr wundern.


    2017/05/29_14:28:50 ist größer als 2017/05/29_13:28:50 und auch größer als 2016/05/29_14:28:50 oder jede andere Zeit vorher


    und kleiner als jede andere Zeit nachher!

    lasst die PIs & ESPs 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)

  • @ noisefloor: Klar könnte ich 3 Werte übergeben. Hab ich in diesem Fall nicht gemacht, weil die Eingabe vom Benutzer aus einer tkinter-entry kommt. Ich hätte es an dieser Stelle vor der Übergabe zerlegen sollten.


    Viele Grüße


    whitechristmas

  • Hallo,


    Unix Timestamp = vergangene Sekunden seit dem 1.1.1970.


    Heißt: die rechnest erst mal mit _absoluten_ Daten. Was ja eigentlich nicht das ist, was du willst. Du willst ja "nur" auf Zeit und Wochentage prüfen, unabhängig von Tag, Monat und Jahr.


    Einen Timestamp kann man ohne Probleme in Datum und Uhrzeit umrechnen und wieder zurück.


    Gruß, noisefloor

  • Hallo,


    das hier müsste funktionieren, allerdings weiß ich nicht woran ich erkenne, ob ich einen Tag dazurechnen muss?


    aktuell=time.strftime("%H:%M:%S")
    jetzt=datetime.datetime.strptime("23:30:00", format) #Uhrzeit wird später durch aktuell ersetzt
    startzeit=datetime.datetime.strptime("23:00:00", format)
    endzeit=datetime.datetime.strptime("01:00:00", format)+ datetime.timedelta(days=1)


    Vergleich:
    jetzt>startzeit und jetzt<endzeit
    Wenn diese Bedingung erfüllt, dann innerhalb des Zeitfensters, ansonsten nicht.


    Vielen Dank.


    whitechristmas

  • Hallo,


    Quote

    allerdings weiß ich nicht woran ich erkenne,


    Erkennen: gar nicht. Du musst für dich bzw. dein Programm eine Konvention festlegen:


    Entweder:
    * Endzeit (in H:M:S) < Startzeit (in H:M:S): Endzeit +1 Tag
    oder
    * Endzeit < Startzeit: nicht erlaubt -> Eingabefehler -> `return False`


    Letzteres bedeutet dann auch automatisch, dass das Zeitfenster _nicht_ datumsübergreifen sein kann. Ersteres bedeutet, dass das Zeitfenster nicht über mehr als einen Tag gehen kann. Wenn beides nicht akzeptabel ist, dann muss du mit Datum + Uhrzeit arbeiten, nicht nur mit der Uhrzeit.


    Gruß, noisefloor

  • Hallo,


    was haltet Ihr von diesem Vorschlag?



    Das müsste so klappen.


    VG whitechristmas

  • Hallo,


    Quote

    was haltet Ihr von diesem Vorschlag?


    Nicht viel, weil du so gut wie alle Tipps ignorierst, die weiter oben stehen.


    Schöner (aber ungetestet):
    [code=php]from datetime import datetime, timedelta


    def time_window_check(*args):


    weekdays = {"Mo": 0, "Di":1, "Mi": 2, "Do": 3 , "Fr": 4, "Sa": 5, "So": 6}
    allowed_weekdays = []
    for item in args[2:]:
    allowed_weekdays.append(weekdays[item])


    start_time = args[0].split(':')
    end_time = args[1].split(':')
    now = datetime.now()
    start = datetime(now.year, now.month, now.day,
    int(start_time[0]), int(start_time[1]), int(start_time[2]))
    end = datetime(now.year, now.month, now.day,
    int(end_time[0]), int(end_time[1]), int(end_time[2]))
    if end_time[0] < start_time[0]:
    end = end + timedelta(days=1)
     
    if now.weekday() in allowed_weekdays:
    if start <= now <= end:
    return 'is in'
    else:
    return 'no time match'
    else:
    return 'no weekday match'


    if __name__ == "__main__":
    user_inputs = ["23:35:00,01:00:00,Mo,Di,Mi,Do,Fr,Sa,So",
    "15:35:00,17:00:00,Mo,Di,Mi,Do,Fr,Sa,So",
    "15:35:00,17:00:00,Sa,So"]
    for user_input in user_inputs:
    res = time_window_check(*user_input.split(','))
    print('{}: {}'.format(user_input, res))[/php]


    Gruß, noisefloor

  • Hallo noisefloor,


    vielen Dank für Deine Rückmeldung, die mich als Hobbyprogrammierer weitergebracht hat. Ich kann sehr viel aus Deinem Skript lernen und werde es auch leicht angepasst für meine Heizungssteuerung, um genau zu sein für meine Pumpe, übernehmen. Aber dass ich aus den obigen Dingen vieles ignoriert habe, dem widerspreche ich. In Deinem Skript erkennt man natürlich eine Qualität auf einer höheren und professionellen Stufe.


    Herzlichen Dank und einen sonnigen Abend.


    whitechristmas


  • Aber dass ich aus den obigen Dingen vieles ignoriert habe, dem widerspreche ich.


    Du übergibst immer noch einen String und hoffst dein split wirft genug parameter ab.
    Du hast "format" übernommen obwohl bootsmann erwähnte dass das nicht gut sei.. Zugegeben, hab ich falsch vorgemacht :blush:
    Du hast "time." weiter verwendet obwohl bootsmann das ebenfalls kommentierte - "aktuell" reicht datetime.datetime.today() und somit wäre "jetzt" auch überflüssig.
    Deine erste if Abfrage unterscheidet sich nicht wirklich zu der aus Beitrag#1 .. was zur Folge hat das du "23 Uhr heute mit 1 Uhr am nächsten Tag" nicht berücksichtigst.

  • Hallo,


    @whitechrismas: zu deiner Beruhigung - ich bin auch nur Hobbyprogrammierer. Ich brauche das weder beruflich noch verdiene ich Geld damit :)


    Was du in deinem Programm IMHO definitiv ändern solltest ist die Datenübergabe. Alles in einem String ist extrem fragil - ein Komma oder Doppelpunkt falsch und schon läuft nichts.


    Die Daten solltest du nicht über eine Zeile aus einem Texteingabefeld ziehen sondern besser:


    * für Start- und Endzeit je drei Felder für Stunde, Minute und Sekunde
    * für jeden Wochentag eine Checkbox (oder Radiobutton oder Multiple Select - was auch immer Tkinter da zu bieten hat.


    Dann kannst du a) die Daten bei der Zeit vor der Übergabe an die Funktion besser validieren (z.B. Stunden muss >= 0 und <= 24 sein, Minuten muss >= 0 und <= 60 sein etc) und du hast garantiert die richtigen Daten für die Wochentage.


    Gruß, noisefloor

  • Hallo noisefloor,


    das Niveau Deiner Skripte unterscheidet sich aber signifikant von meinem Niveau. Ich beschäftige mich jetzt ungefähr seit 1 Jahr mit dem Raspberry und hatte vorher noch keine einzige Zeile Python programmiert. Darf ich fragen, wie man als Hobbyprogrammierer ein derartiges Niveau erreichen kann?


    Du und die anderen haben natürlich recht mit den Tipps. Ich muss aber zu meiner Verteidigung sagen, dass ich nicht alle Tipps direkt eins zu eins umsetzen kann, weil mir schlichtweg die Kenntnisse manchmal fehlen. Ich arbeite aber daran und werde auch Deine Tipps beherzigen und in die Steuerung der Pumpe aufnehmen. Ist halt ein wenig Arbeit, aber nur so kann man "sauberen" Code schreiben.


    Herzlichen Dank an Dich und die anderen die mir geholfen haben.


    Viele Grüße


    whitechristmas

  • Hallo,


    Quote

    Darf ich fragen, wie man als Hobbyprogrammierer ein derartiges Niveau erreichen kann?


    Ich programmiere (hobbymäßig) mit Python hat seit > 10 Jahren - da bleibt schon was hängen.


    Außerdem habe ich mir auch im Laufe der Zeit schon das ein oder andere mittelgroße Projekt für meinen Privatgebrauch programmiert. Es hilft mir auch weiterhin, dass ich a) rel. viele Python-Bücher gelesen habe (ein heißer Tipp für alle ambitionierten Aufsteiger: "Fluent Python" von Luciano Ramalho) und dass ich b) auch im deutschen Python-Form (http://www.python-forum.de) aktiv bin. Da kann man auch als fortgeschrittener noch einiges lernen.


    Ansonsten hilft auch immer: Code in Fachforen zeigen, kritisieren lassen, lernen, beim nächsten Mal besser machen :)


    Gruß, noisefloor