Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi CompareDate gibt immer 1 aus... (https://www.delphipraxis.net/185126-comparedate-gibt-immer-1-aus.html)

Codix32 17. Mai 2015 23:47

Delphi-Version: 2005

CompareDate gibt immer 1 aus...
 
Merkwürdiges Verhalten bei CompareDate

Egal ob der erste Datumwert kleiner, größer, oder gleich dem Zweiten ist:

Der Wert ist immer 1

Hat jemand sowas schon erlebt?

Delphi-Quellcode:
var
  a, b:TDate;
begin
 a:= now;
 if Key = VK_Return then
  begin
   b:= strtodate(Edit1.Text);
   Label1.Caption:= inttostr(compareDate(a,b));
  end;
end;

Popov 18. Mai 2015 00:07

AW: CompareDate gibt immer 1 aus...
 
Bedenke bitte, dass es im Grunde egal ist ob du TDateTime oder TDate oder TTime nimmst. Im Hintergrund ist alles TDateTime. Das ist irreführend, aber TDate speichert nicht Datum, sondern auch Uhrzeit ab.

Wenn du also eine TDate Variable definierst und ihr Now zuweist, dann hast du ihr Datum und Uhrzeit zugewiesen. Die Variable enthält also den TDateTime Wert. Und Now jetzt, selbst wenn es eine TDate Variable ist, und Now eine Millisekunde später, sind nicht gleich.

Lösung:

- Statt Now Funktion Date Funktion nehmen. Die gibt nur das Datum zurück.
- oder Trunc(Now) eingeben. Damit wird die Uhrzeit angeschnitten.

Dalai 18. Mai 2015 00:44

AW: CompareDate gibt immer 1 aus...
 
@Popov: Ich nahm an, weil du Delphi 7 hast, kannst du nachschauen, was CompareDate macht. CompareDate vergleicht nur den Datumsteil, oder anders ausgedrückt: beide Parameter werden einem
Delphi-Quellcode:
Trunc
unterzogen (zumindest für den Vergleich auf Gleichheit).

Die Frage ist also: Was steht in den beiden Variablen a und b drin? Das bekommt man ja leicht raus mit DateToStr.

MfG Dalai

Popov 18. Mai 2015 00:57

AW: CompareDate gibt immer 1 aus...
 
Ich hab vorher den Code nicht ausprobiert, aber CompareDate gibt richtige Ergebnisse raus. Vorausgesetzt die Eingabe ist richtig, z. B. "15.05.2015".

Dejan Vu 18. Mai 2015 06:45

AW: CompareDate gibt immer 1 aus...
 
Nimm mal die 'If Key=' Abfrage raus. Wäre ja denkbar, das es sich nur um ein Wahrnehmungsproblem handelt. Ansonsten stelle das Problem mit einem kleinen Testprogramm dar.
Delphi-Quellcode:
Program Tester;
{$APPTYPE CONSOLE}

Procedure TestCompareDate (a : TDate; bStr : String);
var
  b : TDate;

Begin
  b := StrToDate(bStr);
  Writeln ('CompareDate('DateToStr(a),',',DateToStr(b),')=',CompareDate(a,b));
End;

begin
  TestCompareDate(Now,'1.1.2015');
  TestCompareDate(Now,'1.1.2016');
end.
Trage jeweils deine Testdaten ein, mit denen bei Dir angeblich '1' rauskommt.

Codix32 25. Mai 2015 22:20

AW: CompareDate gibt immer 1 aus...
 
Zitat:

Zitat von Dejan Vu (Beitrag 1301880)
Trage jeweils deine Testdaten ein, mit denen bei Dir angeblich '1' rauskommt.

Dein Beispiel funktioniert bei mir richtig.

Aber hier:
Delphi-Quellcode:
function TForm1.Tagedazwischen(vor, nach:TDate):Integer;
begin
 if compareDate(vor,nach) >= 0 then Result:= daysbetween(vor,nach)
 Else if compareDate(vor,nach) < 0 then Result := -1;
end;
Das Ergebnis bleibt immer 1.
Und eine Meldung lautet:
[Warnung] Unit1.pas(94): W1035 Rückgabewert der Funktion 'TForm1.Tagedazwischen' könnte undefiniert sein

Warum?

Aufgerufewn wird die Funktion hier:
Delphi-Quellcode:
procedure TForm1.Zeitraum(dt:TDate);
var
  vorTag:TDate;                                      
begin
Gauge1.Progress:=0; Gauge2.Progress:=0;Gauge3.Progress:=0;
 vorTag:= strtoDate('17.04.2015');
  if wievieltePackung(Tagedazwischen(dt, vorTag)) >= 1 then
     Gauge1.Progress:= round(100 / 28 * Tagedazwischen(dt, vorTag));
Dabei spielt es keine Rolle ob ich Zeitraum(Now) oder Zeitraum(Date) schreibe.

himitsu 25. Mai 2015 22:50

AW: CompareDate gibt immer 1 aus...
 
Zitat:

Warum?
Formatiere mal den Quelltext ordentlich und dann sieht du es bestimmt.


[edit]
Delphi-Quellcode:
function TForm1.TageDazwischen(vor, nach: TDate): Integer;
begin
  if CompareDate(vor, nach) >= 0 then
    Result := DaysBetween(vor, nach)
  else
    if CompareDate(vor, nach) < 0 then
      Result := -1
    {else
      Result := ???};
end;
:roll:

Delphi-Quellcode:
function TForm1.TageDazwischen(vor, nach: TDate): Integer;
begin
  if CompareDate(vor, nach) >= 0 then
    Result := DaysBetween(vor, nach)
  else
    //if CompareDate(vor, nach) < 0 then // Oder das weglassen, da eh sinnlos, aber das weiß der Compiler ja nicht.
      Result := -1;
end;
:stupid:

Dalai 25. Mai 2015 23:00

AW: CompareDate gibt immer 1 aus...
 
Zitat:

Zitat von Codix32 (Beitrag 1302988)
Aber hier:
Delphi-Quellcode:
function TForm1.Tagedazwischen(vor, nach:TDate):Integer;
begin
 if compareDate(vor,nach) >= 0 then Result:= daysbetween(vor,nach)
 Else if compareDate(vor,nach) < 0 then Result := -1;
end;
Das Ergebnis bleibt immer 1.

Das Ergebnis wovon genau? CompareDate? DaysBetween? Und warum rufst du CompareDate doppelt auf?

Zitat:

Und eine Meldung lautet:
[Warnung] Unit1.pas(94): W1035 Rückgabewert der Funktion 'TForm1.Tagedazwischen' könnte undefiniert sein

Warum?
Weil du zwei if-Bedingungen stehen hast und Result jeweils von der Erfüllung selbiger abhängt. Die Warnung mag zwar für die menschliche Logik nicht zutreffen, aber das weiß der Compiler ja nicht.

Zitat:

Aufgerufewn wird die Funktion hier:
Delphi-Quellcode:
procedure TForm1.Zeitraum(dt:TDate);
var
  vorTag:TDate;                                      
begin
Gauge1.Progress:=0; Gauge2.Progress:=0;Gauge3.Progress:=0;
 vorTag:= strtoDate('17.04.2015');
  if wievieltePackung(Tagedazwischen(dt, vorTag)) >= 1 then
     Gauge1.Progress:= round(100 / 28 * Tagedazwischen(dt, vorTag));

Mach mal eine Ersetzung der Variablen mit deinen Eingabedaten auf Papier (oder im Editor) und überlege, was jeweils bei den Funktionen rauskommt und vergleiche das mit deinen Erwartungen. Kann man auch im Debugger machen, wenn man will.

MfG Dalai

Popov 25. Mai 2015 23:04

AW: CompareDate gibt immer 1 aus...
 
Zitat:

Zitat von himitsu (Beitrag 1302993)
Zitat:

Warum?
Formatiere mal den Quelltext ordentlich und dann sieht du es bestimmt.

Wollte ich gerade auch drauf hinweisen.

Aber vielleicht noch paar Hinweise und Fragen:
Delphi-Quellcode:
function TForm1.Tagedazwischen(vor, nach:TDate):Integer;
begin
 if compareDate(vor,nach) >= 0 then Result:= daysbetween(vor,nach)
 Else if compareDate(vor,nach) < 0 then Result := -1;
end;
Wenn
Delphi-Quellcode:
compareDate(vor,nach) >= 0
größer, gleich Null sind, warum fragst du dann später nochmal mit
Delphi-Quellcode:
compareDate(vor,nach) < 0
ob es kleiner Null ist?

Im Code
Delphi-Quellcode:
compareDate(vor,nach)
steht vor vor nach. In der Funktion
Delphi-Quellcode:
Zeitraum
ist in der Zeile
Delphi-Quellcode:
wievieltePackung(Tagedazwischen(dt, vorTag))
der vorTag an zweiter Stelle. Ich weiß nicht welche Tage in dt stehen, aber ich gehe davon aus, dass es nachTage sind. Vielleicht solltest du für den Fall in der Funktion Tagedazwischen zuerst vor und nach sortieren, also prüfen ob vor auch wirklich das frühere Datum ist. Ansonsten prüfst du drauf ob das spätere Datum vor dem älteren Datum steht. Das Ergebnis wäre in dem Fall -1.

Codix32 25. Mai 2015 23:17

AW: CompareDate gibt immer 1 aus...
 
Zitat:

Zitat von himitsu (Beitrag 1302993)
Zitat:

Warum?
Formatiere mal den Quelltext ordentlich und dann sieht du es bestimmt.


[edit]
Delphi-Quellcode:
function TForm1.TageDazwischen(vor, nach: TDate): Integer;
begin
  if CompareDate(vor, nach) >= 0 then
    Result := DaysBetween(vor, nach)
  else
    if CompareDate(vor, nach) < 0 then
      Result := -1
    {else
      Result := ???};
end;
:roll:

Delphi-Quellcode:
function TForm1.TageDazwischen(vor, nach: TDate): Integer;
begin
  if CompareDate(vor, nach) >= 0 then
    Result := DaysBetween(vor, nach)
  else
    //if CompareDate(vor, nach) < 0 then // Oder das weglassen, da eh sinnlos, aber das weiß der Compiler ja nicht.
      Result := -1;
end;
:stupid:

Ich stehe auf dem Schlauch. Das geht auch nicht:
Delphi-Quellcode:
function TForm1.Tagedazwischen(vor, nach:TDate):Integer;
begin
 if compareDate(vor,nach) >= 0 then
    Result:= daysbetween(vor,nach)
 Else
 //if compareDate(vor,nach) < 0 then Result := -1;
    Result := -1;
end;
Es bleibt 1, auch wenn das erste Datum größer als das 2. ist.
Result := -1 wird nicht ausgegeben.
Die Fehlermeldung ist allerdings weg.

Normalerweise wird die Procedure Zeitraum(date), in der die Function liegt im OnCreate der Form aufgerufen:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  BorderIcons := [biSystemmenu];
  Statusbar1.panels[0].text:='Datum: '+ DatetoStr(Date);
  Statusbar1.panels[1].text:='Woche: '+ InttoStr(WeekOf(Date));
  Zeitraum(Date);         //<- Enthält die Function Tagedazwischen
  fuelleLabels;
end;
Hier die Procedure:
Delphi-Quellcode:
procedure TForm1.Zeitraum(dt:TDate);
var
  vorTag:TDate;                    //<- 1 Tag vor der 1. Tablette
begin
 Gauge1.Progress:=0; Gauge2.Progress:=0;Gauge3.Progress:=0;
 vorTag:= strtoDate('17.04.2015');
  if wievieltePackung(Tagedazwischen(dt, vorTag)) >= 1 then
     Gauge1.Progress:= round(100 / 28 * Tagedazwischen(dt, vorTag));
  if wievieltePackung(daysbetween(dt, vorTag)) >= 2 then
     Gauge2.Progress:= round(100 / 28 * Tagedazwischen(dt, vorTag+incday(27)));
  if wievieltePackung(daysbetween(dt, vorTag)) > 2 then
     Gauge3.Progress:= round(100 / 28 * Tagedazwischen(dt, vorTag+incDay(55)));
     Gauge4.Progress:= round(100 / 84 * Tagedazwischen(dt, vorTag));
  if Tagedazwischen(dt, vortag) <= 84 then
     Label14.caption:= ' Tabletten genommen: ' + inttostr(Tagedazwischen(dt, vortag))+ '/84'
  else
    Label14.caption:= ' Tabletten genommen: 84/84';
    Label15.Caption:= inttostr(compareDate(dt, vortag));
end;

Codix32 25. Mai 2015 23:30

AW: CompareDate gibt immer 1 aus...
 
Zitat:

Zitat von Popov (Beitrag 1302997)
Zitat:

Zitat von himitsu (Beitrag 1302993)
Zitat:

Warum?
Formatiere mal den Quelltext ordentlich und dann sieht du es bestimmt.

Wollte ich gerade auch drauf hinweisen.

......

Im Code
Delphi-Quellcode:
compareDate(vor,nach)
steht vor vor nach. In der Funktion
Delphi-Quellcode:
Zeitraum
ist in der Zeile
Delphi-Quellcode:
wievieltePackung(Tagedazwischen(dt, vorTag))
der vorTag an zweiter Stelle. Ich weiß nicht welche Tage in dt stehen, aber ich gehe davon aus, dass es nachTage sind. Vielleicht solltest du für den Fall in der Funktion Tagedazwischen zuerst vor und nach sortieren, also prüfen ob vor auch wirklich das frühere Datum ist. Ansonsten prüfst du drauf ob das spätere Datum vor dem älteren Datum steht. Das Ergebnis wäre in dem Fall -1.

Danke Popov,

Ein Ergebnis war falsch und deshalb habe ich die Funktion und es konnte nur die Funktion sein, im OnKeyDown Ereignis eines TEdits getestet und eben entdeckt, dass egal, was für ein Datum ich eingebe, ob größer oder kleiner als das 2. Datum immer eine 1 ausgegeben wird, auch wenn die beiden Datums gleich sind.

Hier der einfache Test über ein Editfeld:
Delphi-Quellcode:
procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  t:TDate;
begin
 if key = VK_Return then
   begin
    Try
     if Edit1.Text = '' then
        t := Date
     else
        t:= strtodate(edit1.Text);
     Zeitraum(t);
    Except
     Zeitraum(now);
    end;
   end;
end;

Codix32 25. Mai 2015 23:38

AW: CompareDate gibt immer 1 aus...
 
Ups, ich glaube, ich habe Alzheimer, ich habe den Fehler.

Ich habe tatsächlich ein falsches Datum als festgelegten zweiten Parameter übergeben.
Das ist jetzt wirklich Höchstpeinlich :oops:
Egal, was ich eingegeben habe, das Datum war immer größer.

Ich bitte euch alle um Entschuldigung.

himitsu 25. Mai 2015 23:54

AW: CompareDate gibt immer 1 aus...
 
Und bezüglich des
Delphi-Quellcode:
    Except
     Zeitraum(now);
    end;
Einfach so was "Anderes" machen, ohne dem Bediener seinen Fehler zu nennen, ist nicht die feine englische Art.

Und zusätzlich ist diese Art der Fehlerbehandlung eh "ungünstig", dazumal es sowieso absichtlich ein Delphi-Referenz durchsuchenTryStrToDate oder Delphi-Referenz durchsuchenStrToDateDef gibt, was man besser statt einer Exception verwenden sollte.

Codix32 26. Mai 2015 00:20

AW: CompareDate gibt immer 1 aus...
 
Zitat:

Zitat von himitsu (Beitrag 1303002)
Und bezüglich des
Delphi-Quellcode:
    Except
     Zeitraum(now);
    end;
Einfach so was "Anderes" machen, ohne dem Bediener seinen Fehler zu nennen, ist nicht die feine englische Art.

Himitsu, was meinst Du mit "was Anderes"?
Zitat:

Zitat von himitsu (Beitrag 1303002)
Und zusätzlich ist diese Art der Fehlerbehandlung eh "ungünstig", dazumal es sowieso absichtlich ein Delphi-Referenz durchsuchenTryStrToDate oder Delphi-Referenz durchsuchenStrToDateDef gibt, was man besser statt einer Exception verwenden sollte.

Danke Himitsu, aber so gut bin ich nicht im Programmieren. Ich bewundere allerdings Deine Kenntnisse und habe großen Respekt. Und danke für den Tip. Allerdings hat Delphi-Referenz durchsuchenEditkeydown genau das gemacht, was ich wollte.

Nochmals Allen vielen Dank :oops:

himitsu 26. Mai 2015 01:05

AW: CompareDate gibt immer 1 aus...
 
Fehlerbehandlung sollte mit eine der ersten Dinge sein, die man unbedingt lernen sollte.

Einfach nur das verwendete StrToDate durch eine der beiden fehlerbehandelnden Funktionen austauschen und dafür das Try-Except weglassen.


Oder alles so lassen und blos das Try-Except weglassen. Dann bekommt der Bediener eine Fehlermeldung und der nachfolgende Code wird nur ausgeführt, wenn er die Eingabe richtig macht.
Sonst weiß er garnicht, daß das eingegebene Datum falsch ist und er wundert sich nur, warum dein Programm "Schrott" berechnet, also mit dem "falschen" Datum.



Debugge mal Programme, welche Code wie Diesen benutzen, was auch zu oft in Fremdkomponenten vor kommt.
Da wird man verrückt und will den Programmier davon nur noch erwürgen, weil das Programm so ständig sinnlos irgendwo hängen bleibt.
Delphi-Quellcode:
S := 'abc';
try
  i := StrToInt(S);
except
  i := 0;
end;
ShowMessage(IntToStr(i));
Richtiger wäre es so
Delphi-Quellcode:
S := 'abc';
i := StrToIntDef(S, 0);
ShowMessage(IntToStr(i));
oder
Delphi-Quellcode:
S := 'abc';
if TryStrToInt(S, i) then
  ShowMessage(IntToStr(i));

// oder
S := 'abc';
if not TryStrToInt(S, i) then
  raise Exception.CreateFmt('Was soll denn der Scheiß? "%s" ist doch kein Integer!', [S]);
ShowMessage(IntToStr(i));
Oder halt ganz einfach so und nur arbeiten, wenn in "S" etwas "Ordentliches" drin steht.
Delphi-Quellcode:
S := 'abc';
i := StrToInt(S);
ShowMessage(IntToStr(i));
Aber wenn man mit Exceptions arbeitet, dann grundsätzlich niemals irgendwelche Fehler, vorallem keine Eingabefehler, blindlinks abfangen oder gar durch Irgendwas ersetzen und den Fehler ungezeigt verwerfen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:58 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