Prüfen ob Tag innerhalb einer Tages-range liegt

Gast #4553310
Lesenswert?
• ▲
▼
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
#4553314
Lesenswert?
• ▲
▼
@ 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.
Gast #4553315
Lesenswert?
• ▲
▼
hier ein Code-Ausschnitt wie ich hin verwende:
1
int k = Month > 2 ? Year : Year - 1;
2
int f = Year * 365 + (k + 4) / 4 - k / 100 + k / 400 + (Month - 1) * 30 + (Month + Month / 8) / 2 + (Month > 2 ? Day - 2 : Day) - 1;
f ist dann ein einfacher Zähler für Tage der sich auch leicht 
vergleichen lässt.
Gast #4553317
Lesenswert?
• ▲
▼
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.
Persönliche Seite #4553321
Lesenswert?
• ▲
▼
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.
Gast #4553340
Lesenswert?
• ▲
▼
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.
Gast #4553346
Lesenswert?
• ▲
▼
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
#4553350
Lesenswert?
• ▲
▼
>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
Gast #4553361
Lesenswert?
• ▲
▼
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.
Gast #4553368
Lesenswert?
• ▲
▼
> 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.
Gast #4553372
Lesenswert?
• ▲
▼
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.
Gast #4553378
Lesenswert?
• ▲
▼
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 )))
Gast #4553396
Lesenswert?
• ▲
▼
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
#4553408
Lesenswert?
• ▲
▼
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
  return false ;
4
if (year == start.year) {
5
  if (month < start.month)
6
    return false ;
7
  if (month == start.month) {
8
    if (day < start.day)
9
      return false ;
10
  }
11
}
12
// verify range end
13
if (end.year < year) 
14
  return false ;
15
if (end.year == year) {
16
  if (end.month < month)
17
    return false ;
18
  if (end.month == month) {
19
    if (end.day < day)
20
      return false ;
21
  }
22
}
23
return true ;

Ein normalisiertes integer Format ist allerdings praktischer. Also 
Sekunden seit..., ich nehme gern die Julian Day Number 
(https://en.wikipedia.org/wiki/Julian_day).
Gast #4553409
Lesenswert?
• ▲
▼
> 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
Moderator Persönliche Seite #4553431
Lesenswert?
• ▲
▼
Frank M. schrieb:
> Beide Daten in einen String der Form "YYYYMMDD" umrechnen und beide
> Strings einfach strcmp() übergeben.

Beispiel:
1
  char tim1[9];
2
  char tim2[9];
3
  int  diff;
4

5
  sprintf (tim1, "%04d%02d%02d", start.year, start.month, start.day);
6
  sprintf (tim2, "%04d%02d%02d", end.year, end.month, end.day);
7

8
  diff = strcmp (tim1, tim2);
9

10
  if (diff < 0)
11
  {
12
      // kleiner
13
  }
14
  else if (diff > 0)
15
  {
16
      // größer
17
  }
18
  else
19
  {
20
      // gleich
21
  }


P.S.

Das war falsch:

Return-Werte:

>  -1 Datum1 kleiner Datum2
>   0 Datum1 gleich  Datum2
>   1 Datum1 größer  Datum2

Richtig ist:

  negativ  Datum1 kleiner Datum2
  0        Datum1 gleich  Datum2
  positiv  Datum1 größer  Datum2
#4553450
Lesenswert?
• ▲
▼
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.
#4553485
Lesenswert?
• ▲
▼
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:
1
make_scalar(year,month,day) { return (day-1) + 31 * ( (month-1) + 12 * year ) ; }

Das liest sich einfach und ist damit quasi selbst dokumentierend. Man 
muss lediglich den Fall des Überlaufs ausschließen.
Gast #4553498
Lesenswert?
• ▲
▼
@ 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.
Gast #4553525
Lesenswert?
• ▲
▼
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
(Firma: Vescomp) #4553530
Lesenswert?
• ▲
▼
Cube_S schrieb:
> hier ein Code-Ausschnitt wie ich hin verwende:
>
1
> int k = Month > 2 ? Year : Year - 1;
2
> int f = 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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren