Einzelnen Beitrag anzeigen

ASM

Registriert seit: 16. Aug 2004
165 Beiträge
 
Delphi 7 Enterprise
 
#11

AW: 0.0 ist kein gültiger Zeitstempel

  Alt 11. Aug 2011, 00:31
Da der Datentyp Date keine Zeitangabe besitzt, wird er, vermute ich mal, nicht durch eine Fließkommazahl repräsentiert, sondern durch einen Integer. Und damit wäre eine Fließkommazahl kein gültiger Date Wert.

Das Thema ist nicht mehr ganz taufrisch, bedarf aber doch deutlicher Korrektur:

Zunächst einiges Grundsätzliche:
Zwar wird der Wert für Date() tatsächlich intern (innerhalb der Funktion TryEncodeDate()) aus der Summe ausschließlich reiner Integerwerte berechnet, er wird aber dennoch eindeutig als Typ TDateTime abgelegt und ist somit de facto vom Typ Double.

So zeigt auch der Code
Code:
showmessage(format('Ausgabewert Date() belegt %d Bytes',[sizeof(date())]));
an, dass der von Date() zurückgegebene Wert tatsächlich 8 Bytes belegt (zur Erinnerung: Integervariablen belegen 4 Bytes)

Von den 8 Bytes einer TDateTime-Variablen werden 4 Bytes für den exponentiellen Anteil, also die Tageszeit verwendet und 4 Bytes für die Mantisse, also das aktuelle Tagedatum, gemäß dem detaillierten Format des Zeitstempels:
Bit Inhalt
-------------------
00-04 Sekunde
05-10 Minute
11-15 Stunde
16-20 Tag
21-24 Monat
25-31 Jahr

Bei Date() werden die Nachkommastellen, welche in TDateTime die Tageszeit definieren, grundsätzlich immer mit 0 belegt.
Dagegen werden bei Time() die Vorkommastellen grundsätzlich immer mit der Bytefolge belegt, die dem Datum 30.12.1899 entspricht, also auf das Datum bezogen ist, welches Delphi seit Delphi 2 als Referenzwert seiner TDateTimezählung verwendet (dies aus Gründen der Kompatibilität zu der zuvor von MS eingeführten OLE 2.0 Automation).

Dementsprechend wirft der Code
Code:
showmessage(format('Date() = %d',[date()]));
die EConvertError-Exception "Format '%d' ungültig oder nicht kompatibel mit Argument",
wogegen der Code
Code:
showmessage(format('Date() = %f',[date()]));
ganz normal ausgibt (am 10.08.2011): "Date() = 40765,00"


Das von Angel4585 beschriebene Problem entsteht nun vielmehr durch einen Bug in der Funktionskette StrToDate() -> TryStrToDate() -> ScanDate() -> ScanNumber(): In ScanNumber() wird die Stringlänge der eingebenen Jahreszahl auf maximal 4 Zeichen gekürzt, sodass eben von der tatsächlich eingegebenen Jahreszahl 11572 nur die gekürzte Jahreszahl 1157 übrigbleibt. Diese aber liegt unterhalb der Referenzjahreszahl 1899 (Wert = 0), wodurch die in TryEncodeDate(Y, M, D, Date) berechnete Date-Variable negativ wird und dadurch letztendlich die beschriebene EConvertError-Exception ausgelöst wird.

Von diesem Problem sind alle Funktionen betroffen, die einen Datumstring in eine TDateTime- bzw. TDate-Variable konvertieren (wie StrToDateTime() und StrToDate()): diese sind also nur für Jahreszahlen bis 9999 einsetzbar!

Interessanterweise ist dem gegenüber als maximaler TDate-Wert 2146790053 erlaubt, was dem Datum 11.Juli 46907 (!) entspricht. Die Konversion eines solch hohen TDate-Wertes in eine Stringvariable ist also von dem o.g. Problem nicht betroffen (obwohl auch hierbei der eigentliche Maxint von 2147483647 nicht erreicht werden kann, allerdings dann keine Exception ausgelöst wird, sondern das Datum oberhalb eines TDate von 2146790053 nur rigoros und ohne Warnung auf 00.00.0000 gesetzt wird).
  Mit Zitat antworten Zitat