Forum: Mikrocontroller und Digitale Elektronik Ermitteln ob Zeit zwischen zwei Uhrzeiten ist


von Fabi R. (efabi)


Lesenswert?

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.

von nicht so (Gast)


Lesenswert?

Fabi R. schrieb:
> if(TimeNow zwischen StartTime und zwischen EndTime){ ... }

Nö.

if(TimeNow > StartTime AND TimeNow < EndTime){ ... }

von Slippin J. (gustavo_f)


Lesenswert?

StartTime = 20 Uhr
EndTime = 7 Uhr
TimeNow = 22 Uhr

nicht so schrieb:
> if(TimeNow > StartTime AND TimeNow < EndTime){ ... }

ergibt false!

Eher sowas:
if(EndTime < StartTime) EndTime += 24
if(TimeNow > StartTime AND TimeNow < EndTime){ ... }

: Bearbeitet durch User
von nicht so (Gast)


Lesenswert?

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.

von Joachim B. (jar)


Lesenswert?

nicht so schrieb:
> 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.

http://www.cplusplus.com/reference/ctime/difftime/
http://www2.hs-fulda.de/~klingebiel/c-stdlib/time.htm

von nicht so (Gast)


Lesenswert?

Joachim B. schrieb:
> nicht so schrieb:
>> 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.
>
> http://www.cplusplus.com/reference/ctime/difftime/
> http://www2.hs-fulda.de/~klingebiel/c-stdlib/time.htm

Ja und jetz? Genau davon red ich ja, ein Zeitstempel ala unix-time. 
Damit kann man schön rechnen und Vergleiche aufstellen.

von Edi R. (edi_r)


Lesenswert?

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.)

von pegel (Gast)


Lesenswert?

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.

von pegel (Gast)


Lesenswert?

Ach ja, wenn der Tagbetrieb wieder anfängt, Stunden stellen nicht 
vergessen.

von Achim S. (Gast)


Lesenswert?

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)

von Edi R. (edi_r)


Lesenswert?

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".

von Achim S. (Gast)


Lesenswert?

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.

von pegel (Gast)


Lesenswert?

Edi R. schrieb:
> Die Betonung liegt auf "Nacht-Modus".

Ja, genau.
Wenn das Stille-Flag gesetzt ist, nicht klappern.

von Achim S. (Gast)


Lesenswert?

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.

von Wolfgang (Gast)


Lesenswert?

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:
> ...

von Hauspapa (Gast)


Lesenswert?

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

von Leo C. (rapid)


Lesenswert?

Hauspapa schrieb:
> 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.

Ja :-)
1
if (StartTime < EndTime)
2
    BeQuiet = (TimeNow > StartTime && TimeNow < EndTime);
3
else
4
    BeQuiet = (TimeNow < StartTime || TimeNow > EndTime);

In C läßt sich das noch weiter kürzen, aber ob es dann noch hübcher ist?

von re (Gast)


Lesenswert?

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)

von A. S. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Wolfgang (Gast)


Lesenswert?

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

von re (Gast)


Lesenswert?

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)

von Rolf M. (rmagnus)


Lesenswert?

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. ;-)

von A. S. (Gast)


Lesenswert?

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
int n, s, e; /* now, start, end */
2
3
/* mit tausch */
4
int h=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) return n>s && n<e; /* start und Ende an einem Tag */
10
else    return n>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:
1
return s<e ? n>s&&n<e : n>s||n<e;

von Fabi R. (efabi)


Lesenswert?

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!

von Xaver (Gast)


Lesenswert?

Beim nächsten solchen Problem lohnt es sich evtl. auch nochmal über die 
Inhalte der Vorlesung zur Diskreten Mathematik nachzudenken. Stichworte: 
Gruppe, Ring, Körper

https://de.wikipedia.org/wiki/Abelsche_Gruppe
https://de.wikipedia.org/wiki/Ring_(Algebra)
https://de.wikipedia.org/wiki/K%C3%B6rper_(Algebra)
https://de.wikipedia.org/wiki/Endlicher_K%C3%B6rper

Dann wird das auch wieder was mit Subtraktion und Vergleichen unter 
Modulo...

von my2ct (Gast)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

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.

von foobar (Gast)


Lesenswert?

1
int between(unsigned now, unsigned start, unsigned end)
2
{
3
    // make use of unsigned wrap-arounds
4
    return now - start < end - start;
5
}

von Jemand (Gast)


Lesenswert?

Ich würde es ja so machen:
1
bool is_nighttime(uint32_t begin, uint32_t end, uint32_t curr_time)
2
{
3
    float time_center = ((float)begin + (float)end) / 2.0f;
4
    float complex center_hand = cexpf(I*time_center*2.0f*(float)M_PI/86400.0f);
5
    float complex time_hand = cexpf(I*curr_time*2.0f*(float)M_PI/86400.0f) * conjf(center_hand);
6
    float threshold = crealf(center_hand * cexpf(-I*(float)begin*2.0f*(float)M_PI/86400.0f));
7
    return ((crealf(time_hand) - threshold) > 0) ^ (begin > end);
8
}

von my2ct (Gast)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

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.

von foobar (Gast)


Lesenswert?

> 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 ;-)

von Route_66 H. (route_66)


Lesenswert?

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).

von heute kein (Gast)


Lesenswert?

1
switch(hour){
2
   case 22 ... 23: pause();break;
3
   case 0 ... 7: pause();break;
4
   default: start();break;
5
}

von heute kein (Gast)


Lesenswert?

1
if (h == 22){
2
  stop = 1;
3
}
4
if (h == 7){
5
  stop = 0;
6
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.