Hallo
Ich stehe vor der Aufgabe zu prüfen, ob ein bestimmter Tag innerhalb
einer Datums-range liegt.
Also z.B. der 10. zwischen dem 5. und dem 15. .
Dieser Fall ist recht einfach und wird in meinem Algorithmus derzeit mit
1
if((day>=date_from.day)&&(day<=date_to.day))
abgearbeitet. Allerdings schlägt diese Abfrage natürlich beim
Monatswechsel also z.b. date_from.day=31 und date_to.day=1 fehl. Obwohl
der Tag (31.) innerhalb des Bereichs liegt.
Habt ihr mir eine gute Idee, wie ich diesen Fall handeln kann?
Gruß,
Bean
@ Mr Bean (Gast)
>Ich stehe vor der Aufgabe zu prüfen, ob ein bestimmter Tag innerhalb>einer Datums-range liegt.
Du meinst einen Date-bereich?
>Habt ihr mir eine gute Idee, wie ich diesen Fall handeln kann?
Man muss den Tag in den Tag des Jahres umrechnen, dann hat man einen
einheitlichen Zahlenbereich. Oder man muss in Einzelprüfungen den Monat
mit berücksichtigen.
Du nennst selbst das Stichwort: Fall.
Der übliche Weg, den Programmierer dann gehen, ist, sich die
verschiedenen Fälle zu überlegen. In Deinem Fall (hi hi) gibt es nur
zwei mögliche Fälle. Du hast sie genannt.
Das ist nicht einfach die Lösung, aber Du kommst selbst darauf, wenn Du
ein wenig darüber nachdenkst, meine ich.
Allerdings gibt es ein anderes Problem dabei, das Du nicht genannt hast.
Entweder spielt es in Deinem Fall keine Rolle oder Du hast nicht daran
gedacht. Die Monate haben verschiedene Länge. Und im Fall des Februars
hängt die Länge noch von der Jahreszahl ab.
Normiere Deine Datumsangaben z.B. auf x. Tag im Jahr und vergleiche
dann.
Wenn jahresübergreifende Daten vorkommen (zwischen 25.12.16 und 3.1.17),
dann musst Du auf Tag seit einem ausreichend lange in der Vergangenheit
liegenden Datum normieren, und dann vergleichen.
Für Datumsberechnungen lohnt es sich immer, eine Normierungs- und
"Entnormierungs"-Funktion zu haben, also einer, die aus einem Datum eine
Tagesnummer und aus einer Tagesnummer wieder ein Datum erzeugt.
Damit lässt sich auch leicht die Aufgabe "Nenne mir das Datum in 41
Tagen" lösen.
Die Sache mit den Normierungsfunktionen (z.B. auf die Anzahl Tage seit
dem 1.1.1970 oder so ähnlich) ist natürlich die beste Möglichkeit. Damit
ist alles berücksichtigt, was normalerweise auftritt.
Ok, vielen Dank für eure Antworten.
die mktime() Funktionen aus time.c wollte ich mir egentlich sparen. Da
diese ja doch etwas Resourcen kosten. Aber habe mir schon fast gedacht,
dass es am Ende doch darauf raus läuft, wenn man sicher alle Fälle
berücksichtigen möchte.
Danke
Gruß,
Bean
>Die Sache mit den Normierungsfunktionen (z.B. auf die Anzahl Tage seit>dem 1.1.1970 oder so ähnlich) ist natürlich die beste Möglichkeit. Damit>ist alles berücksichtigt, was normalerweise auftritt.
Ja bis ein Datum vor dem 1.1.1970 umzurechnen ist.
Gruß J
Jonas B. schrieb:>>Die Sache mit den Normierungsfunktionen (z.B. auf die Anzahl Tage seit>>dem 1.1.1970 oder so ähnlich) ist natürlich die beste Möglichkeit. Damit>>ist alles berücksichtigt, was normalerweise auftritt.>> Ja bis ein Datum vor dem 1.1.1970 umzurechnen ist.>> Gruß J
Das versteht sich, meiner Meinung nach, ja von selbst und ist keiner
Erwähnung wert.
> Das versteht sich, meiner Meinung nach, ja von selbst und ist keiner> Erwähnung wert.
So selbstverständlich ist das nicht. Wenn's richtig gemacht ist, könnte
man auch mit negativen Zahlen rechnen.
Es ist immer ein Problem, wie tief man bei solchen Fragen und den
Antworten darauf geht. Bei der obigen Formel ist ihr Geltungsbereich
nicht angegeben. Was wäre dann mit Daten vor dem 15.10.1582?
Die Behauptung - "bis man dan Daten vor 1970 berechnen muss" - an sich
ist wertlos, wenn man dann nicht auf das aufgeworfene Problem eingeht.
Der TO hat vermutlich gar nicht die Vorkenntnisse um das einzuschätzen.
Und bevor er mktime erwähnt hat, wusste man gar nicht, ob sein Problem
nicht erst einmal nur darin liegt einen Vergleich für - im weitesten
Sinne - Modulo-Bereiche zu formulieren.
> Wenn man es richtig macht ...
Was ist richtig, was ist falsch? Das hängt von dem Kenntnisstand ab.
Aber wenn ich eine Funktion postuliere, die eine Berechnung für Werte
seit dem 1.1.1970 berechnet dann ist klar, dass sie nicht
notwendigerweise für Werte davor gültige Resultate ergibt.
Der Satz fängt darüber hinaus falsch an. Die Voraussetzung war ja
gerade, dass der Definitionsbereich damit anfängt. Damit ist die
Funktion ihrer Definition nach "richtig" und es gibt kein "richtiger".
Es ist wirklich ärgerlich, dass hier alles und jedes relativiert wird.
Ohne Erklärung, völlig unnötig, unvollständig und falsch.
Florian schrieb:> Die Sache mit den Normierungsfunktionen (z.B. auf die Anzahl Tage seit> dem 1.1.1970 oder so ähnlich) ist natürlich die beste Möglichkeit. Damit> ist alles berücksichtigt, was normalerweise auftritt.
Wenn er eine 32-bit Variable nimmt, dann wird es ab dem 9. Januar 2038
3:14:08 Uhr auch Probleme geben.
Was ist so schwer daran das ganze mit einer if Abfrage mit ein paar and
zu klären:
if (((day >= date_from.day) && (day <= date_to.day )) &&
((month >= date_from.month) && (month <= date_to.month)) &&
((year >= date_from.year) && (year <= date_to.year )))
Karl schrieb:> if (((day >= date_from.day) && (day <= date_to.day )) &&> ((month >= date_from.month) && (month <= date_to.month)) &&> ((year >= date_from.year) && (year <= date_to.year )))
Dann check mal was bei deinem tollen Konstrukt rauskommt wenn:
Das Datum der 20.4.2016 ist und
date_from der 28.02.2016
date_to der 4.5.2016
Sollte eine einfache Prüfung von Anfang und Ende sein. Also (hopefully)
sowas in der Art:
1
// verify range start
2
if(year<start.year)
3
returnfalse;
4
if(year==start.year){
5
if(month<start.month)
6
returnfalse;
7
if(month==start.month){
8
if(day<start.day)
9
returnfalse;
10
}
11
}
12
// verify range end
13
if(end.year<year)
14
returnfalse;
15
if(end.year==year){
16
if(end.month<month)
17
returnfalse;
18
if(end.month==month){
19
if(end.day<day)
20
returnfalse;
21
}
22
}
23
returntrue;
Ein normalisiertes integer Format ist allerdings praktischer. Also
Sekunden seit..., ich nehme gern die Julian Day Number
(https://en.wikipedia.org/wiki/Julian_day).
> Wenn er eine 32-bit Variable nimmt, dann wird es ab dem 9. Januar 2038> 3:14:08 Uhr auch Probleme geben.
Nicht mit obiger Formel, denn die berücksichtigt nur ganze Tage und hat
mit 32-Bit kein Problem. Und es sind nur 2 Zeilen
Der Andere schrieb:> Das Datum der 20.04.2016 ist und> date_from der 28.02.2016> date_to der 04.05.2016
O.K., dann falt so:
if (year >= year.from) &&
(month > from.month || (month = from.month && day >= from.day))
...
Noch eine Alternative:
Beide Daten in einen String der Form "YYYYMMDD" umrechnen und beide
Strings einfach strcmp() übergeben.
Return-Werte:
-1 Datum1 kleiner Datum2
0 Datum1 gleich Datum2
1 Datum1 größer Datum2
Such mal mit dem Stichwort:
"Julianisches Datum" bzw.
"Julian day" für Ausländer.
Dafür gibt es fertige und wahrscheinlich geprüfte Funktionen im Netz.
Ich glaube, Ihr denkt alle viel zu kompliziert!
Wenn die Aufgabe wirklich nur das ist, wie im Eingangspost beschrieben,
kann man die Datum-Zahlen auch einfach in numerische Variablen schieben
(Jahr auf die höchstwertigen Bits, Tage auf die niederwertigen) und die
Zahlen mit einem stinknormalen, numerischen Vergleichsoperator
verarbeiten.
@ Thomas Elger
Bei dem von mir vorgeschlagenen Julianischen Tag kommt eine "lineare"
Ganzzahl zum Tragen, die sich einfachen Vergleichen unterziehen lässt.
S.Siebenhaar schrieb:> Bei dem von mir vorgeschlagenen Julianischen...
Ok, wären wir hier in einem EDV-Forum, fände ich die Lösung auch gut,
aber wir sind ja im Mikrocontroller-Forum und da würde ich eine simplere
und effektivere Lösung, ohne komplizierte Umrechnung von D-M-Y in eine
Zahl bevorzugen.
Thomas E. schrieb:> Ich glaube, Ihr denkt alle viel zu kompliziert!
Stimmt! Bei dem Vergleich spielt es ja keine Rolle ob das Skalar
durchgehend gültige Werte aufweist, oder nicht. Statt Bits würde ich
aber mit den Wertebereichen (day=0..30,month=0..11) skalieren, also:
@ Thomas Elger
Wenn ich, aus welchen Gründen auch immer, die time-lib nicht einbinden
möchte, der TO hat seine Zielplattform ja noch nicht verraten, würde ich
mir die "übliche" Formel einfach mal ansehen.
Wird diese nicht 10000 mal pro Sekunde durchlaufen, so sehe ich auch auf
schwachbrüstigen µP's kein Problem.
Im Übrigen hast Du ja allen kundgetan, was Du nicht machen würdest. Wie
wäre es mal mit einem konstruktiven Vorschlag.
S.Siebenhaar schrieb:> Im Übrigen hast Du ja allen kundgetan, was Du nicht machen würdest. Wie> wäre es mal mit einem konstruktiven Vorschlag.
Dus schreibst um 10:45 gegen seinen Vorschlag von 10:36 und kannst dich
um 11:13 schon nicht mehr daran erinnern?
Vieleicht mal zum Arzt gehen :-)
Also,
vielen Dank allen die sich an der Diskusion beteiligen.
Ich habe eine für mich arbeitende Lösung gefunden. Ich berechne mit
timestamps mit mktime(). Das ist vielleicht nicht die performanteste,
aber ich kann mir sicher sein dass alle Fälle abgedeckt sind.
Zumindest solange ich in dem notwendigen Zahlenraum bleibe. Also >1970.
Ich verabschiede mich dann hier aus dem Thread. ;-)
Vielen Dank wie gesagt allen noch einmal. THUMBS_UP
Gruß,
Bean
Cube_S schrieb:> hier ein Code-Ausschnitt wie ich hin verwende:>
1
>intk=Month>2?Year:Year-1;
2
>intf=Year*365+(k+4)/4-k/100+k/400+(Month-1)*30
3
>+(Month+Month/8)/2+(Month>2?Day-2:Day)-1;
4
>
> f ist dann ein einfacher Zähler für Tage der sich auch leicht> vergleichen lässt.
Ja, sowas ähnliches habe ich auch, nur ist es für DayOfWeek, für
einfaches Vergleichen von 2 Tagen ist es viel zu viel Rechnen.
Wenn es um die Geschwindigkeit und Resources geht, lässt sich
sein Problem am schnellsten mit einfachen if-vergleichen lösen.
Etwa so:
Mikro 7. schrieb:> Sollte eine einfache Prüfung von Anfang und Ende sein.
Seine Lösung hat im ungünstigsten Fall 10 einfache Vergleiche, wenn
jeder Schritt 2us braucht, sind es max. 20us. In Assembler würde man
dafür weniger als 60Bytes brauchen (geschätzt). Und ein guter Compiler
sollte auch nicht viel mehr brauchen.