![]() |
StringToDateTime macht murx
Hallo Zusammen,
ich bin gerade über was gestolpert, was ich mir nicht so richtig erklären kann. Folgender Beispielcode:
Delphi-Quellcode:
Bediene ich die Funktion falsch oder was ist hier los?
procedure TDlg_Main.BtnTestClick(Sender: TObject);
var tmp : Tdatetime; aFormat : TFormatSettings; begin tmp := StrToDateTime('21.12.1993 00:09:59'); //Liefert 21.12.1993 00:09:59 und OK GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, aFormat); aFormat.ShortDateFormat := 'yyyy-mm-dd'; aFormat.ShortTimeFormat := 'hh:nn:ss'; aFormat.DateSeparator := '-'; aFormat.TimeSeparator := ':'; tmp := StrToDateTime('1993-12-21 00:10:00', aFormat); // Liefert 21.12.1993 00:09:59 NICHT OK tmp := VarToDateTime('1993-12-21 00:10:00')// Liefert 21.12.1993 00:09:59 NICHT OK end; |
AW: StringToDateTime macht murx
unter XE bei mir nicht nachvollziebar
|
AW: StringToDateTime macht murx
Bei mir XE2/XE3 funktioniert es. :gruebel:
Da du die RTL-Codes besitzt, kannst du aber mal StrToDateTime debuggen und schauen, ob du den Rechenfehler findest. Was du aber "falsch" machst, ist das dir Delphi deine Variable wegoptimieren könnte, da du sie nie ausliest, sondern immer nur befüllst.
Delphi-Quellcode:
[add]
procedure TDlg_Main.BtnTestClick(Sender: TObject);
var tmp : Tdatetime; aFormat : TFormatSettings; begin tmp := StrToDateTime('21.12.1993 00:09:59'); //Liefert 21.12.1993 00:09:59 und OK if temp = 0 then ; // billiger Hack, im Delphi daran zu hindern diese Variable wegoptimieren zu können (den ganze "nutzlose" IFs optimieren die immernoch nicht weg) ... tmp := StrToDateTime('1993-12-21 00:10:00', aFormat); // Liefert 21.12.1993 00:09:59 NICHT OK if temp = 0 then ; tmp := VarToDateTime('1993-12-21 00:10:00')// Liefert 21.12.1993 00:09:59 NICHT OK if temp = 0 then ; end; Statt dem IF mal folgendes verwenden, welches zusätzlich noch Millisekunden, Mikrosekunden und sinnloser Weise ein paar Nanosekunden anzeigt.
Delphi-Quellcode:
ShowMessage(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', tmp) + StringReplace(Format('.%7.3n', [Frac(tmp * MSecsPerDay) * 1000]), ' ', '0', [rfReplaceAll]));
|
AW: StringToDateTime macht murx
Delphi-Quellcode:
Sieht der Source bei euch auch so aus???
function TryStrToDateTime(const S: string; out Value: TDateTime): Boolean;
var Pos: Integer; NumberPos: Integer; BlankPos, LastBlankPos, OrigBlankPos: Integer; LDate, LTime: TDateTime; Stop: Boolean; begin Result := True; Pos := 1; LTime := 0; // jump over all the non-numeric characters before the date data ScanToNumber(S, Pos); // date data scanned; searched for the time data if ScanDate(S, Pos, LDate) then begin // search for time data; search for the first number in the time data NumberPos := Pos; ScanToNumber(S, NumberPos); // the first number of the time data was found if NumberPos < Length(S) then begin // search between the end of date and the start of time for AM and PM // strings; if found, then ScanTime from this position where it is found BlankPos := Pos - 1; LastBlankPos := BlankPos; Stop := False; while (not Stop) and (BlankPos < NumberPos) do begin // blank was found; scan for AM/PM strings that may follow the blank if (BlankPos > 0) and (BlankPos < NumberPos) then begin Inc(BlankPos); // start after the blank OrigBlankPos := BlankPos; // keep BlankPos because ScanString modifies it Stop := ScanString(S, BlankPos, TimeAMString) or ScanString(S, BlankPos, 'AM') or ScanString(S, BlankPos, TimePMString) or ScanString(S, BlankPos, 'PM'); // ScanString jumps over the AM/PM string; if found, then it is needed // by ScanTime to correctly scan the time BlankPos := OrigBlankPos; end // no more blanks found; end the loop else Stop := True; // search of the next blank if no AM/PM string has been found if not Stop then begin LastBlankPos := BlankPos; BlankPos := PosEx(' ', S, LastBlankPos); end; end; // loop was forcely stopped; check if AM/PM has been found if Stop then // AM/PM has been found; check if it is before or after the time data if BlankPos > 0 then if BlankPos < NumberPos then // AM/PM is before the time number Pos := BlankPos else Pos := NumberPos // AM/PM is after the time number else Pos := NumberPos // the blank found is after the the first number in time data else Pos := NumberPos; // get the time data Result := ScanTime(S, Pos, LTime); // time data scanned with no errors if Result then if LDate >= 0 then Value := LDate + LTime // Hier wird 21.12.1993 + 30.12.1899 00:10:00 = 21.12.1993 00:09:59 else Value := LDate - LTime end // no time data; return only date data else Value := LDate; end // could not scan date data; try to scan time data else Result := TryStrToTime(S, Value) end; |
AW: StringToDateTime macht murx
Um er kurz zu machen, kann man bei mir mit foldendem Code auf eine Falschberechnung auslösen:
Delphi-Quellcode:
var
tmp : TDateTime; tmp2: TDateTime; begin tmp := StrToDateTime('21.12.1993'); tmp2 := StrToDateTime('30.12.1899 00:10:00'); if (tmp= 0) or (tmp2 = 0) then; tmp := tmp + tmp2; // 21.12.1993 00:09:59 end Ich habe das ganze jetzt mal mit nem ShowMessage(DateTimeToStr(tmp)) ausgegeben lassen und siehe da, der Debugger zeigt mir einen falschen Wert an. Die Ausgabe des Dialogs ist korrekt. Fazit: Traue nie einem Debugger. Danke für eure Unterstützung |
AW: StringToDateTime macht murx
'korrekt' ist so ne Sache, denn die TDateTime-Werte sind Floating-Point und Du hast es hier mit einem klassischen FP-Rundungsproblem zu tun.
Die Zeit '10:00:00' wird als 10/24 = 5/6 repräsentiert, was eine rationale Zahl mit unendlicher Periode ist und somit nicht 100% korrekt als floating point darzustellen ist. Hinzu kommt noch, das viele einfache Dezimalzahlen auch nicht sauber als FP darzustellen sind. Blöde Sache. Der TDateTime-Wert ist also garantiert nicht exakt '10 Uhr morgens', sondern irgendwie ein paar Nanomilliwasweissichsekunden geringer. Der Debugger wird nun so blöd programmiert sein, und irgend eine Frickelformatierung verwenden (jedenfalls wohl nicht 'DateTimeToStr') und deshalb etwas anderes anzeigen. Aber auch die DateTimeToStr-Variant zeigt nicht genau den richtigen Wert an, sondern rundet (aka schummelt) auch ein wenig. Nur eben so, das Du zufrieden bist. Und darauf kommts ja an ;-) |
AW: StringToDateTime macht murx
Fazit: Time-zu-String-Funktionen runden vorwiegend ab.
Es wäre ja fatal, wenn man nur "runden" würde, denn dann würde die Anzeige garnicht mehr stimmen. z.B. mit der "extrem" drastischen Variante ab 0,5 Stunden die Stundenanzeige aufrunden, denn dann würde aus 4:35 plötzlich 5 Uhr werden. Auch wäre es fahrlässig, wenn man z.B. im StringToDateTime 'ne halbe Millisekunde aufrechnen würde, damit die Anzeigen stimmen, denn wenn man mit Zeiten rechnet, dann könnte sich diese "zusätzliche" Zeit sehr schnell aufschaukeln. Was man aber machen könnte, wenn man z.B. 'ne halbe oder 10-tel Millisekunde nur für die Anzeige aufrechnet, womit das Abrundungsverhalten sich dort nicht derart negativ zeigt. Bruchteil der Millisekunde deswegen, weil TDateTime auf eine Genauigkeit von einer Millisekunde ausgelegt ist. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:55 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz