Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Kalenderwochen Funktion Falsch? (https://www.delphipraxis.net/104498-kalenderwochen-funktion-falsch.html)

Eppos 5. Dez 2007 12:48


Kalenderwochen Funktion Falsch?
 
Hallo zusammen,

ich benutze hier aus der Code-Lib folgende Funktion:

Hier zeigt Alex_ITA01 wie es möglich ist, anhand eines Datums die zugehörige Kalenderwoche zu ermitteln. Für Delphi 6 und höher, geht dies genau so gut mit WeekOfTheYear (Unit: DateUtils), doch für die Benutzer älterer Delphi-Versionen ist dies mit folgendem Code möglich:

Delphi-Quellcode:
function GetKW(Date: TDateTime): Integer;
var
   Day: Integer;
   Y, M, D: Word;
begin
  Day := DayOfWeek(Date) - 1;
  if (Day <= 0) then
    Day := 7;
  DecodeDate(Date + 4 - Day, Y, M, D);

  result := round(((Date + 8 - Day) - EncodeDate(Y, 1, 1)) / 7);
end;
Wenn ich aber diese verwende, wird mir die Kalenderwoche für den 10.01.2008 falsch berechnet?!
@Edit: Bekomme als Ergebnis '1', sollte aber 2 ausspucken...

Hat jemand eine Idee warum das so ist?

Ich habe die WeekOfTheYear Funktion nicht zur Verfügung!

Danke

DP-Maintenance 5. Dez 2007 12:50

DP-Maintenance
 
Dieses Thema wurde von "Matze" von "Programmieren allgemein" nach "Sonstige Fragen zu Delphi" verschoben.
Delphi-Frage

Eppos 5. Dez 2007 12:58

Re: Kalenderwochen Funktion Falsch?
 
... ausser man beachtet, dass es sich um eine Deutsche KW/Datum handelt.

negaH 5. Dez 2007 16:46

Re: Kalenderwochen Funktion Falsch?
 
Also ich habe damals, und das schon zu Delphi 2 Zeiten, exakt diese Funktion entwickelt. Sie funktioniert richtig, teste mal

Delphi-Quellcode:
  ShowMessage(IntToStr(WeekOfDate(EncodeDate(2008, 1, 10))));
bei mir kommt da wie erwartet 2 raus.

Gruß Hagen

x000x 6. Jan 2010 09:33

Re: Kalenderwochen Funktion Falsch?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Moin moin,

mir ist gestern aufgefallen, dass diese funktion wohl doch fehlerhaft ist.
Das Problem liegt wohl hier:
Delphi-Quellcode:
((Date + 8 - Day) - EncodeDate(Y, 1, 1)) / 7
Folgender aufruf zeigt den Fehler:
Delphi-Quellcode:
ShowMessage(IntToStr(WeekOfDate(StrToDateTime('06.01.2010 11:59:59')))+#13#10+
            IntToStr(WeekOfDate(StrToDateTime('06.01.2010 12:00:00'))));

Mithrandir 6. Jan 2010 09:47

Re: Kalenderwochen Funktion Falsch?
 
Moin Peter,

stimmt, die Funktion ist nicht richtig. Hagens Funktion hingegen arbeitet tadellos. ;)

x000x 6. Jan 2010 09:51

Re: Kalenderwochen Funktion Falsch?
 
Delphi-Quellcode:
function DayOfWeekGerman(ADate: TDateTime): Integer;
begin
  Result := DayOfWeek(ADate) -1;
  if Result <= 0 then Result := 7;
end;

function WeekOfDate(A: TDateTime): Integer;
var
  Day: Integer;
  Y,M,D: Word;
begin
  Day := DayOfWeekGerman(A);
  DecodeDate(A +4 -Day, Y, M, D);
  Result := Round(((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7);
end;

procedure TForm1.Button1Click(Sender: TObject);
var dat : TDateTime;
begin
  ShowMessage(IntToStr(WeekOfDate(StrToDateTime('06.01.2010 11:59:59')))+#13#10+
              IntToStr(WeekOfDate(StrToDateTime('06.01.2010 12:00:00'))));
end;
ich komme hierbei leider zum selben ergebnis :-/

Schreibt man den Wert von
Delphi-Quellcode:
((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7
in einen double, dann sieht man auch warum.

Bei '06.01.2010 11:59:59' ergibt dann
Delphi-Quellcode:
((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7 = 1.4999983466
Bei '06.01.2010 12:00:00' ergibt dann
Delphi-Quellcode:
((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7 = 1.5
und da
Delphi-Quellcode:
Round(1.5) = 2
entsteht der Fehler.

Mithrandir 6. Jan 2010 10:06

Re: Kalenderwochen Funktion Falsch?
 
Dann sollte der Nachkommateil vielleicht lieber weggefiltert werden. :gruebel: Statt Delphi-Referenz durchsuchenRound also Delphi-Referenz durchsuchenTrunc

Amateurprofi 6. Jan 2010 21:44

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von Daniel G
Dann sollte der Nachkommateil vielleicht lieber weggefiltert werden. :gruebel: Statt Delphi-Referenz durchsuchenRound also Delphi-Referenz durchsuchenTrunc

Nein, das bringt nichts.
Hagens Routine arbeitet fehlerfrei, solange der TDateTime Wert ganzzahlig ist.
Wenn der TDateTime-Wert einen Zeitanteil hat, bringt sie an bestimmten Tagen dann fehlerhafte Resultate, wenn der Zeitanteil >= 12 Stunden ist.
Also sollte am Anfang der Routine eine Zeile
Delphi-Quellcode:
A := Int(A);
eingefügt werden.

Vielleicht sollte man die letzte Zeile ändern
von
Delphi-Quellcode:
Result := Round(((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7);
in
Delphi-Quellcode:
Result := Trunc(0.5+((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7);
weil das besser zeigt, was gerechnet werden soll.
M.E. sollte die Routine dann so aussehen:
Delphi-Quellcode:
function DayOfWeekGerman(ADate: TDateTime): Integer;
begin
  Result := DayOfWeek(ADate) -1;
  if Result <= 0 then Result := 7;
end;

function WeekOfDate(A: TDateTime): Integer;
var
  Day: Integer;
  Y,M,D: Word;
  n:extended;
begin
  A := Int(A);
  Day := DayOfWeekGerman(A);
  DecodeDate(A +4 -Day, Y, M, D);
  Result := Trunc(0.5+((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7);
end;

Mithrandir 7. Jan 2010 08:11

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von Amateurprofi
Nein, das bringt nichts.

Und im selben Posting machst du es dann doch. ;)

Amateurprofi 7. Jan 2010 09:58

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von Daniel G
Zitat:

Zitat von Amateurprofi
Nein, das bringt nichts.

Und im selben Posting machst du es dann doch. ;)

Daniel,
lies doch mal etwas genauer, wie ich das Round(...) ersetzt habe.
Ich habe nicht einfach (wie von dir vorgeschlagen) das "Round" durch "Trunc" ersetzt sondern durch Trunc(0.5 + ...).
Du schlugst vor, mit Trunc den Nachkommateil abzuschneiden.
Ich runde ab, wenn der Nachkommaanteil < 0.5 ist und auf, wenn er >= 0.5 ist.
Round würde dann, wenn der Nachkommaanteil = 0.5 ist, auf die nächstgelegene gerade Zahl runden.
Bei dieser Routine wird dieser Fall nicht eintreten, weil bei einer Division eines Integerwertes durch 7 der Nachkommateil nie 0.5 sein kann.
Ich halte es aber für "sauberer", hier nicht Round zu verwenden, damit klar ist was gerechnet werden soll.

Mithrandir 7. Jan 2010 10:14

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von Amateurprofi
Du schlugst vor, mit Trunc den Nachkommateil abzuschneiden.

Ja, denn der wird ja nicht gebraucht. Oder? Ich bräucht einen Beweis, welche der beiden Varianten nun richtig ist. Den find ich aber nicht. Bislang bringen beide bei mir dasselbe Ergebnis.

mkinzler 7. Jan 2010 10:15

Re: Kalenderwochen Funktion Falsch?
 
Wenn nur dern Datumbereich beachtet werden soll muss man abschneiden als Trunc()

Mithrandir 7. Jan 2010 10:25

Re: Kalenderwochen Funktion Falsch?
 
Büdde was? :gruebel:

mkinzler 7. Jan 2010 10:29

Re: Kalenderwochen Funktion Falsch?
 
Die Berechnung ist falsch, wenn der TDateTime eine Zeitangabe enthält. Deshalb muss man diese abschneiden

x000x 7. Jan 2010 11:47

Re: Kalenderwochen Funktion Falsch?
 
Moin moin,

Zitat:

Zitat von Daniel G
...Ich bräucht einen Beweis, welche der beiden Varianten nun richtig ist...

Ich versuche es mal...

Vom übergebenen Datum interessiert ja nur der Datumteil, also die Stellen vor dem Komma.
Ob ich nun z.B. 40184 durch y teile oder 40184.xxxxx durch y, die Vorkommastellen vom Ergebnis bleiben gleich.
Und da bei
Delphi-Quellcode:
((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7
nur unser übergebenes Datum Nachkommastellen haben könnte,
können wir auch bei dem Ergebnis den Nachkommaanteil ignorieren.

Also reicht es, das Round durch Trunc zu ersetzen, wie du schon im Beitrag #8 geschrieben hast.

Mithrandir 7. Jan 2010 12:00

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von x000x
Also reicht es, das Round durch Trunc zu ersetzen, wie du schon im Beitrag #8 geschrieben hast.

Danke. :) Denn ich kann immer noch nicht nachvollziehen, warum es nun wichtig sein soll, 0.5 dazuzuaddieren. :gruebel:

mkinzler 7. Jan 2010 12:12

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Danke. Smile Denn ich kann immer noch nicht nachvollziehen, warum es nun wichtig sein soll, 0.5 dazuzuaddieren. Grübelnd...
Wäre sogar falsch, denn dann wäre aber Mittag der nächste Tag.

Amateurprofi 7. Jan 2010 14:30

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von Daniel G
Zitat:

Zitat von Amateurprofi
Du schlugst vor, mit Trunc den Nachkommateil abzuschneiden.

Ja, denn der wird ja nicht gebraucht. Oder? Ich bräucht einen Beweis, welche der beiden Varianten nun richtig ist. Den find ich aber nicht. Bislang bringen beide bei mir dasselbe Ergebnis.

Bei mir nicht.
Beispiele:
01.01.2010 : 52 (Richtig : 53)
02.01.2010 : 52 (Richtig : 53)
03.01.2010 : 52 (Richtig : 53)
Alle Tage des Jahres 2009.

Im Zeitraum 15.10.1582 bis 31.12.2499 bringt ein einfaches Trunc(...) an 144918 (von 335006) Tagen ein falsches Ergebnis. (Zumindest wenn ich bei all dem, was ich gemacht habe nicht völlig gepennt habe)
Der Fehler tritt bei mir auf:
1) An allen Tagen eines Jahres, wenn der 01.01. ein Dienstag, Mittwoch oder Donnerstag ist. (144269 Mal)
2) Am 01.01. und 02.01. eines Jahres, wenn der 01.01. ein Samstag ist und in die 53. Woche des Vorjahres fällt. (60 Mal)
3) Am 01.01., 02.01. und 03.01. eines Jahres, wenn der 01.01. ein Freitag ist. (396 Mal)
4) Am 30.12. und 31.12. eines Jahres, wenn der 30.12. ein Montag ist. (60 Mal)
5) Am 31.12. eines Jahres, wenn er ein Montag ist. (133 Mal)

Mithrandir 7. Jan 2010 14:38

Re: Kalenderwochen Funktion Falsch?
 
Ok, dann nehm ich zurück, was ich gesagt hab. Meine Testfälle waren einfach nicht richtig konstruiert. Wenn es keine größeren Proteste gibt, werde ich das morgen im Laufe des Tages in die Funktion in der CL einarbeiten.

Amateurprofi 7. Jan 2010 20:07

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von x000x
Moin moin,

Zitat:

Zitat von Daniel G
...Ich bräucht einen Beweis, welche der beiden Varianten nun richtig ist...

Ich versuche es mal...

Vom übergebenen Datum interessiert ja nur der Datumteil, also die Stellen vor dem Komma.
Ob ich nun z.B. 40184 durch y teile oder 40184.xxxxx durch y, die Vorkommastellen vom Ergebnis bleiben gleich.
Und da bei
Delphi-Quellcode:
((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7
nur unser übergebenes Datum Nachkommastellen haben könnte,
können wir auch bei dem Ergebnis den Nachkommaanteil ignorieren.

Also reicht es, das Round durch Trunc zu ersetzen, wie du schon im Beitrag #8 geschrieben hast.

Vielleicht versuchst du es noch einmal.
Die Nachkommastellen dürfen keinesfalls einfach ignoriert werden - es sei denn man legt Wert auf Fehler.

Amateurprofi 7. Jan 2010 20:28

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von mkinzler
Zitat:

Danke. Smile Denn ich kann immer noch nicht nachvollziehen, warum es nun wichtig sein soll, 0.5 dazuzuaddieren. Grübelnd...
Wäre sogar falsch, denn dann wäre aber Mittag der nächste Tag.

Nein. Es wäre falsch, ein Trunc durchzuführen, ohne vorher 0.5 zu addieren.

Ich hab mal in die Funktion die Zwischenwerte eingefügt, da wird dann wohl jedem klar, daß ein simples Trunc nicht ausreicht.

Aufruf : XWeekOfDate(EncodeDate(2009,01,01));

Delphi-Quellcode:
function xWeekOfDate(A: TDateTime): Integer;
var
  Day: Integer;
  Y,M,D: Word;
  n:extended;
begin
  A := Int(A); // A=39814
  Day := DayOfWeek(A) -1; // Day=4
  if Day <= 0 then Day := 7; // Day=4
  DecodeDate(A +4 -Day, Y, M, D); // Y=2009
  Result := Trunc(((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7); // Result = 0
  // A+8-Day = 39818
  // EncodeDate(Y,1,1) = 39814
  // (A+8-Day)-EncodeDate(Y,1,1) = 4
  // ((A+8-Day)-EncodeDate(Y,1,1))/7 = 0.5714285713
  // Result = Trunc(0.5714285713)
  // Result = 0
  Result := Trunc(0.5+((A +8 -Day) - EncodeDate(Y, 1, 1)) / 7); // Result = 1
  // Result = Trunc(0.5 + 0.5714285713)
  // Result = Trunc(1.0714285713)
  // Result = 1
end;
Ein Trunc (ohne vorher 0.5 zu addieren) würde als Resultat 0 ergeben.
Ein Trunc (bei vorheriger addition von 0.5) ergibt das korrekte Resultat 1.

Im Stillen habe ich gehofft, daß negaH mal ein paar Kommentare abgibt - scheint ihm wohl zu albern zu sein.
Übrigens @negaH : eine sehr elegante Lösung hast da gefunden.

Es wäre schön, wenn alle, die so oft "aus der Hüfte geschossene" Kommentare abgeben, vorher prüfen, ob das, was sie schreiben wollen auch korrekt ist.

Mithrandir 7. Jan 2010 20:40

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von Amateurprofi
Im Stillen habe ich gehofft, daß negaH mal ein paar Kommentare abgibt - scheint ihm wohl zu albern zu sein.

Hagen ist schlichtweg nicht mehr sooft in der DP unterwegs, da er mit Delphi nicht mehr soviel am Hut hat, wie er selbst mal geschrieben hat. ;)

Im Übrigen sollte man innerhalb von 24 Stunden den http://www.delphipraxis.net/template.../icon_edit.gif-Button nutzen, wenn man noch etwas hinzufügen möchte. ;)

Amateurprofi 7. Jan 2010 23:44

Re: Kalenderwochen Funktion Falsch?
 
Zitat:

Zitat von Daniel G
Zitat:

Zitat von Amateurprofi
Im Stillen habe ich gehofft, daß negaH mal ein paar Kommentare abgibt - scheint ihm wohl zu albern zu sein.

Hagen ist schlichtweg nicht mehr sooft in der DP unterwegs, da er mit Delphi nicht mehr soviel am Hut hat, wie er selbst mal geschrieben hat. ;)

Im Übrigen sollte man innerhalb von 24 Stunden den http://www.delphipraxis.net/template.../icon_edit.gif-Button nutzen, wenn man noch etwas hinzufügen möchte. ;)

Danke für den Hinweis bezüglich Edit-Button. Aber ich habe im Momeent nicht vor noch etwas hinzuzufügen.
Falls sich der Hinweis darauf bezieht, daß ich kurz hintereinander zwei Beiträge geschrieben habe : Ich hab das ganz bewußt in zwei Beiträge gepackt, weil ich auf zwei Beiträge von zwei Usern reagiert habe.

x000x 8. Jan 2010 01:21

Re: Kalenderwochen Funktion Falsch?
 
Moin moin,

@Klaus: :thumb:

Zitat:

Zitat von Amateurprofi
...
Es wäre schön, wenn alle, die so oft "aus der Hüfte geschossene" Kommentare abgeben, vorher prüfen, ob das, was sie schreiben wollen auch korrekt ist.

Ich gebe dir Recht, nur war ich wirklich überzeugt, dass meine Aussage bezüglich der "nachkommastellenignoranz" korrekt war
(warum auch immer). Ich hätte wohl erstmal versuchen sollen, den dahinter liegenden Algo zu verstehen :oops:


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:33 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz