Hallo,
ich habe derzeit ein Projekt am Laufen bei der ich eine Uhr mit einer
elektromechanischen Anzeige baue. Da diese Anzeige relativ laut ist,
wenn die Einzelnen Segmente (rück-)gesetzt werden, will ich einen
Nacht-Modus implementieren.
Dabei muss hierfür festgestellt werden, ob sich ein Zeitpunkt (TimeNow)
zwischen der Startzeit (Start) und Endzeit (End) befindet.
Dies scheint eigentlich eine relativ simple Frage zu sein, jedoch schein
ich einfach nicht auf eine optmale Lösung zu kommen.
Eine Lösung die für den Laufenden Betrieb der Uhr funktioniert, habe ich
bereits gefunden. Jedoch wird der Nacht-Modus mittels einer App (Android
Studio) eingestellt und kann somit zu jedem beliebeigen Zeitpunkt
aktiviert werden.
Also bedarf es einer Lösung nach folgendem Pseudo-Code:
if(TimeNow zwischen StartTime und zwischen EndTime){ ... }
Ich befürchte, dass eine Lösung dafür viele Verzweigungen und Abfragen
benötiigen wrid, was ich gerne vermeiden würde.
Für die Vereinfachung können Minuten und Sekunden hierfür erstmal
vernachlässigt werden.
Ich bin mir sicher, dass es dafür eine einfache Lösung gebene muss,
vielleicht sogar eine vorgefertigte Funktion von der ich nichts weiß.
Ist ja schließlich kein neues Problem.
Vielen Dank für die Antworten im Vorraus.
Slippin J. schrieb:> nicht so schrieb:>> if(TimeNow > StartTime AND TimeNow < EndTime){ ... }>> ergibt false!
Das kommt drauf an wie TO Zeiten darstellt. Angegeben hat er ja nichts
verwertbares. Ich bin mal von einer konventionellen Timestamp ala Unix
ausgegangen, da brauch ich mir um Überläufe nach 24h oder ähnlichem Spaß
keine Gedanken machen.
Wenn die Uhrzeit nur "human readable" verfügbar ist, würde ich die
zunächst mal in eben so eine timestamp umwandeln, sonst gibt's wirklich
Gefrickel.
Wenn man sowieso nur die Stunden betrachten will, ist eine Konvertierung
in ein anderes Format (Timestamp) unnötig. Ich würde einfach prüfen, ob
TimeNow zwischen der Endzeit und der Startzeit liegt, nicht umgekehrt.
Slippin J. schrieb:> StartTime = 20 Uhr> EndTime = 7 Uhr> TimeNow = 22 Uhr
if (TimeNow > EndTime && TimeNow < StartTime) { ... }
oder falls erforderlich negiert:
if (!(TimeNow > EndTime && TimeNow < StartTime)) { ... }
(Wir wissen nichts von der verwendeten Programmiersprache, also gehe ich
erstmal von C aus.)
Ohne Programmiersprache würde ich:
- zu jeder vollen Stunde prüfen, ob:
-- Nachtbetrieb anfängt -> Stille Flag setzen
-- Tagbetrieb anfängt -> Stille Flag zurücksetzen
Dann einfach vor jedem geklapper das Stille Flag abfragen.
Edi R. schrieb:> Ich würde einfach prüfen, ob> TimeNow zwischen der Endzeit und der Startzeit liegt, nicht umgekehrt.
Teste deine Lösung mal mit folgenden Kombinationen:
Start: 20:00 Ende: 07:00
Start: 20:00 Ende: 22:00
Start: 02:00 Ende: 07:00
Dann erkennst du das Problem des TO
pegel schrieb:> - zu jeder vollen Stunde prüfen, ob:> -- Nachtbetrieb anfängt -> Stille Flag setzen> -- Tagbetrieb anfängt -> Stille Flag zurücksetzen
Das wäre auch mein Vorschlag gewesen: wie es eine typische Zeitschaltuhr
macht. Sie merkt sich, ob sie gerade deaktiviert ist (Nachtmodus auf 1)
Falls ja fragt sie ab, ob timenow == Ende ist und setzt ggf. den
Nachtmodus auf 0
Falls nein fragt sie ab ob timenow == Start ist und setzt ggf. den
Nachtmodus auf 1
Der Nachteil dabei: wenn um 20:30 mit der App z.B. die Startzeit von
21:00 auf 19:00 geändert wird, dann wird es fast einen ganzen Tag
dauern, bis die nächste Aktivierung des Nachtmodus beginnt. In dem Fall
müsste also zusätzlich der Nachtmodus "manuell" aktiviert werden.
Will man beim Umstellen der Start/Ende-Zeiten die App den Nachtmodus
aktivieren lassen, hat man das Problem nur an diese Stelle verschoben.
Möglicherweise ist der TO schon genau an dieser Stelle, denn er schrieb:
Fabi R. schrieb:> Eine Lösung die für den Laufenden Betrieb der Uhr funktioniert, habe ich> bereits gefunden. Jedoch wird der Nacht-Modus mittels einer App (Android> Studio) eingestellt und kann somit zu jedem beliebeigen Zeitpunkt> aktiviert werden.
Ich fürchte in dem Fall bleibt dir nur
- eine Zeitdarstellung, die mit dem Überlauf um Mitternacht ohne
Verrenkungen klarkommt
- oder die Fallunterscheidung mit diversen verzweigungen (liegen beide
Zeiten vor Mitternacht, beide nach Mitternacht oder eine vor und eine
nach Mitternacht)
Achim S. schrieb:> Edi R. schrieb:>> Ich würde einfach prüfen, ob>> TimeNow zwischen der Endzeit und der Startzeit liegt, nicht umgekehrt.>> Teste deine Lösung mal mit folgenden Kombinationen:> Start: 20:00 Ende: 07:00> Start: 20:00 Ende: 22:00> Start: 02:00 Ende: 07:00> Dann erkennst du das Problem des TO
Die beiden letzten Beispiele sind nicht das Problem des TO:
Fabi R. schrieb:> Da diese Anzeige relativ laut ist,> wenn die Einzelnen Segmente (rück-)gesetzt werden, will ich einen> Nacht-Modus implementieren.
Die Betonung liegt auf "Nacht-Modus".
Achim S. schrieb:> Ich fürchte in dem Fall bleibt dir nur> - eine Zeitdarstellung, die mit dem Überlauf um Mitternacht ohne> Verrenkungen klarkommt> - oder die Fallunterscheidung mit diversen verzweigungen (liegen beide> Zeiten vor Mitternacht, beide nach Mitternacht oder eine vor und eine> nach Mitternacht)
Ach ja: so viele Verzweigungen sind es wahrscheinlich gar nicht. Es
reduziert sich wahrscheinlich auf die Abfrage:
if (start<ende) {
if (timenow>start and timenow<ende) ...
}
else{
if (timenow > start or timenow<ende) ...
}
Kannst ja mal durchspielen, ob das für alle Varianten aufgeht.
Edi R. schrieb:> Die beiden letzten Beispiele sind nicht das Problem des TO:
Echt jetzt: kennst du niemanden, der nicht öfters mal nach Mitternacht
ins Bett geht? Du definierst dir das Problem so zurecht, wie du es
einfach lösen kannst.
Achim S. schrieb:> if (start<ende) {> if (timenow>start and timenow<ende) ...> }> else{> if (timenow > start or timenow<ende) ...> }>> Kannst ja mal durchspielen, ob das für alle Varianten aufgeht.
Was für ein Gefrickel.
Slippin J. schrieb:> Eher sowas:> ...
Ich Versuchs auch mal für Polling:
if (StartTime < EndTime)
{
if (TimeNow > StartTime && TimeNow < EndTime)
{ BeQuiet=1 }
Else
{ Bequiet=0 }
}
Else
{
if (TimeNow < StartTime || TimeNow > EndTime)
{ BeQuiet=1 }
Else
{ Bequiet=0 }
}
Geht sicher auch hübscher.
Viel Erfolg
Hauspapa
Das Problem taucht genauso auf, wenn man z.B. Winkel o.ä. vergleicht,
ist also eigentlich schon oft gelöst worden.
(a) Am nachvollziehbarsten ist es imho, erstmal das Vergleichsintervall
zu normalisieren:
Wenn der Endzeitpunkt "vor" dem Startzeitpunkt liegt, dann ist er
offenbar einen Tag später.
StartTime = 20 Uhr
EndTime = 7 Uhr --> EndTime´ = 7+24=31h
(EndTime = 23Uhr --> (bleibt so))
(b) TimeNow ist auch zu normalisieren, aber leider ist das nicht so
eindeutig, weil TimeNow ja auch vor StartTime liegen darf. Nehmen wir
dazu ersatzweise ein 24h-Intervall, das symmetsrisch zum
"Nachtintervall" liegt,
also: [(StarTime+EndTime´)/2 +/-12h]
hier also [13:30 bis 37:30].
Wenn TimeNow außerhalb des Intervalls liegt, liegt, werden 24h
dazugezählt oder abgezogen, bis es drin liegt.
Hier: TimeNow= 0h..13h --> TimeNow´=24h..37h.
14h..24h --> (bleibt so)
Jetzt kann man ohne Fallunterscheidung vergleichen, ob
Startime < TimeNow´ < EndTime´ .
HTH
(re)
I
re schrieb:> (a) Am nachvollziehbarsten ist es imho, erstmal das Vergleichsintervall> zu normalisieren:
Oder halt konkret mit 24 Uhr für mitterNacht zu rechnen:
Also, wenn Start <=Stop, dann ganz normal (start<now&&now<Stop). Das
deckt hier alle "Sonderfälle".
Sonst (Start>Stop, also Mitternacht dazwischen):
now>Start||now<Stop
Keine Umrechnung, keine 24h.
Achim S. schrieb:> Der Nachteil dabei: wenn um 20:30 mit der App z.B. die Startzeit von> 21:00 auf 19:00 geändert wird, dann wird es fast einen ganzen Tag> dauern, bis die nächste Aktivierung des Nachtmodus beginnt. In dem Fall> müsste also zusätzlich der Nachtmodus "manuell" aktiviert werden.
Das ist z.B. bei vielen Heizungssteuerungen der Fall. Daher gibt es eine
Taste für manuelles Togglen der Nachtabsenkung.
Rolf M. schrieb:> Warum nicht einfach so:>
Wenn Ende vor Start liegt -> 24h dazuzählen
Wenn Now vor Start liegt -> 24h dazuzählen
Prüfen, ob Now zwischen Start und Ende liegt
A. S. schrieb:> Also, wenn Start <=Stop, dann ganz normal (start<now&&now<Stop). Das> deckt hier alle "Sonderfälle".>> Sonst (Start>Stop, also Mitternacht dazwischen):> now>Start||now<Stop
Da hast Du recht.
Ich hatte komplizierterweise noch im Auge, festzustellen, ob man gerade
vor, oder nach der "Nachtzeit" ist, aber das war gar nicht gefragt. Mein
Fehler.
(re)
re schrieb:> Ich hatte komplizierterweise noch im Auge, festzustellen, ob man gerade> vor, oder nach der "Nachtzeit" ist, aber das war gar nicht gefragt.
Nach der Nachtzeit ist vor der Nachtzeit. ;-)
Rolf M. schrieb:> Warum nicht einfach so:>> Wenn Ende vor Start liegt, Start und Ende vertauschen und die Bedingung> der Prüfung, ob TimeNow im Intervall ist, invertieren.
Das ist prinzipiell richtig, meist wird der geschriebene Code damit aber
sowohl größer als auch komplizierter. Beispiel:
1
intn,s,e;/* now, start, end */
2
3
/* mit tausch */
4
inth=0;/* hilfsvariable zum Tausch und als Merker */
5
if(e<s){h=s;s=e;e=h;h=1;}/* swap start-end und merker setzen */
6
return(n>s&&n<e)^h;/* Auswertung mit Merker */
7
8
/* ohne tausch, wie von mir oben empfohlen */
9
if(s<e)returnn>s&&n<e;/* start und Ende an einem Tag */
10
elsereturnn>s||n<e;/* … Ende am nächsten Tag */
zudem gibt es noch ein größeres Problem, wenn man die Grenzen (kleiner
versus kleinergleich) korrekt definieren will. Dann setzt man das in die
beiden Formeln unten einfach intuitiv ein. Mit dem ^ wird das
anspruchsvoller ;-)
Und wer gegen 2 returns ist, als Einzeiler:
Wow! So viele Anworten, danke!
Ich ich habe im Laufe des Tages einige Ideen ausprobiert und verwende
jetzt tatsächlich die Veriante von A. S., da mir die am simpelsten
erscheint.
Wenn man den ganzen Tag nur vor dem Code sitzt sieht man manchmal die
bools vor lauter Einsen und Nullen nicht mehr.
Danke noch mal für die tolle Unterstützung, @alle!
A. S. schrieb:> Das ist prinzipiell richtig, meist wird der geschriebene Code damit aber> sowohl größer als auch komplizierter.
Das Programm wird nicht kürzer, wenn du kryptische
Einbuchstabenbezeichnungen für die Variablen verwendest und die
Bedeutung nur bei der Deklaration als Kommentar dahinter schreibst.
Einzig die Lesbarkeit nimmt ab.
my2ct schrieb:> Einzig die Lesbarkeit nimmt ab.
Das Beispiel sollte auch kein vorzeigeCode sein, sondern Anzahl bzw
Unterschiede/Komplexität der Operationen zeigen. Das wird durch
sprechende Bezeichner und aufgeräumte Anweisungen nicht deutlicher. Aber
mach gerne zum Vergleich beide Wege in schön.
Jemand schrieb:> Ich würde es ja so machen:> ...
Sehr hübsch - so kommen bei einem simplen Ganzzahlproblem auch die
komplexen Zahl mal richtig zur Geltung ;-)
Mit den paar Float-Operationen wird man bei angemessener
Aufrufhäufigkeit trotzdem selbst einen 8-Bit µC nicht wirklich fordern
können. Allenfalls einer Leere im Flash lässt sich damit wirkungsvoll
entgegen treten.
foobar schrieb:> int between(unsigned now, unsigned start, unsigned end)> {> // make use of unsigned wrap-arounds> return now - start < end - start;> }
Genial. War mir nicht klar, dass das auch bei begrenztem Zahlenbereich
so einfach ist.
> begrenztem Zahlenbereich
Das Praktische an dem Problem ist, dass es vollkommen egal ist, wie lang
ein Tag ist. Warum also nicht 256^sizeof(unsigned) Stunden? Dann spart
man sich das (von Xaver oben erwähnte) explizite Modulo-Gehampel ;-)
Hallo!
Zeitschaltuhr als Beispiel wurde bereits genannt.
Es gibt ja Exemplare, die haben für jede Viertelstunde einen "Bippus"
der anzeigt: On/Off.
Hier wäre das für die Stundenschaltung ein 24-Bit-Feld. Dann käme die
ganze Schalterei auch nicht durcheinander, wenn während des Laufs eine
Zeit manuell geändert wird. Man muss nur bei jedem Uhrstellen das
Bitfeld ebenfalls "Nachstellen".
Das gesamte Prinzip funktioniert auch bei automatischer Zeitnachstellung
im Hintergrund (Sommer-/Winterzeit).