![]() |
Zeitenberechnungs-Unit, bitte um Tests
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo allerseits,
viele kennen sicherlich das saublöde Problem, dass die Delphi-eigenen Zeitkonvertierungsfunktionen in den meisten Fällen bei Zeiten > 24 Stunden den Dienst verweigern und dann behaupten, es wäre keine gültige Eingabe oder ähnliches. Ich habe mich bei der Programmierung eines Tools über diese Beschränkung maßlos ärgern müssen und habe mir deshalb eine kleine Unit kreiert, die dieses Manko ausbügeln soll. Und genau um diese geht es hier. Hier erstmal die allgemeinen Infos: function timestring: addiert die übergebenen dezimal dargestellten Zeiten ('1,25' oder '2,3654') und gibt die Summe in der Form 13:15:56 als String zurück function decintime5: wandelt eine Dezimalzahl in eine Zeit der Form 23:56 um und gibt sie als String zurück function decintime8: wandelt eine Dezimalzahl in eine Zeit der Form 23:56:24 um und gibt sie als String zurück function timeindec: wandelt einen als String übergebenen Time-Wert vom Format '13:50:34' in einen Dezimalwert um function decodetime5: Diese Function zerlegt einen String der Art '25:15' in seine Einzelbestandteile h, min und das unabhängig von der 24 Stunden Grenze der Delphi-eigenen Routinen. Zusätzlich ist result der Funktion der real-Wert der zerlegten Zeit. function decodetime8: Diese Function zerlegt einen String der Art '25:15:26' in seine Einzelbestandteile h, min, sek und das unabhängig von der 24 Stunden Grenze der Delphi-eigenen Routinen. Zusätzlich ist result der Funktion der real-Wert der zerlegten Zeit. Ich möchte euch bitten, diese Unit einmal zu testen, da ich trotz eigener Tests freilich bislang nicht wirklich sicher bin, alle Fehlerquellen ausgeschlossen zu haben. Bitte beachtet auch die Bemerkungstexte an den jeweiligen Funktionen, da manchmal noch ein zusätzlicher Hinweis drin steht, auf was geachtet werden muß. Ich bitte um Rückmeldungen. Bingo |
Re: Zeitenberechnungs-Unit, bitte um Tests
Hallo BingoBongo,
eine schöne Sourcecode-Orgie hast Du da erzeugt ;-) Um ehrlich zu sein, wird mir nicht klar, welche Werte diese Dezimalzahlen annehmen können. Also wenn Du schreibst Zitat:
Um ehrlich zu sein, reicht dafür folgender Fünfzeiler aus:
Delphi-Quellcode:
(runtergetippert, ungetestet).
var h, m, s: Integer;
zeit: TTime; begin h := Trunc(indec); m := Trunc(Frac(indec) * 60); s := Trunc(Frac(indec) * 3600) mod 60; zeit := EncodeTime(h, m, s); result := FormatDateTime('hh:nn:ss', zeit); exit; Deine erste Funktion timestring() hat 30 Übergabeparameter ohne Default-Wert, d.h. man muss wirklich bei jedem Aufruf alle 30 Parameter angeben. Wenn man schon so eine Funktion braucht, dann wäre es sinniger, die Parameter als offenes Array angeben zu können:
Delphi-Quellcode:
Der Aufruf erfolgt dann mit AddTimes(["1,5", "2,5", "3,5"]);
function AddTimes(arr: array of String): String;
var i: Integer; zeit: Double; begin zeit := 0; for i:=Low(arr) to High(arr) do zeit := zeit + StrToFloat(arr[i]); result := decintime8(zeit); end; In der Funktion decodetime verwendest du einen konstanten String ziffern und testest, ob ein einzelnes Zeichen Deiner Eingabe in diesem String enthalten ist. Schöner wäre es, Ziffern als Menge von Chars zu definieren (ziffern = ['0'..'9']; ) und dann mit "if timestring[i] in ziffern then..." zu testen. Ich weiß zwar nicht, ob das performanter ist, aber es sieht im Quellcode schöner aus ;-) Anstelle von
Delphi-Quellcode:
solltest Du besser
result:= hour * H + minute * M + sekunde * S;
Delphi-Quellcode:
verwenden, da dies genau die dafür vorgesehene Funktion ist.
result := EncodeTime(hour, minute, sekunde);
So, ich hoffe, das hilft Dir ein wenig. |
Re: Zeitenberechnungs-Unit, bitte um Tests
Und schau dir außerdem mal die Unit DateUtils an.
|
Re: Zeitenberechnungs-Unit, bitte um Tests
Diese Funktionen sind hauptsächlich dazu gedacht, die Zeitformatierungsbegrenzung, die wohl Delphi-eigen ist, zu umgehen. Oder hast du schonmal versucht, 2 Zeiten, z.Bsp. 12:30:35 und 15:17:56 zu addieren? Selbstverständlich das ganze in hh:mm:ss. Diese 5-stellige Ausgabe ist dann als hh:mm zu verstehen.
Die Konvertierungsfunktionen von Delphi sind nämlich bedauerlicherweise scheinbar auf maximal < 24 Stunden begrenzt. Diese Funktionen entstanden, weil ich an einem kleinen Proggi werkle, bei dem massig Zeiten addiert werden müssen. Und da bin ich auf diese ärgerliche Hürde gestoßen. Und was die Unit DateUtils betrifft, habe ich in der Hilfe nichts gefunden, was diese Rechengrenze umgeht. Falls ich mich darin irre, so gebt mir bitte einen Tipp, wonach ich genau! suchen sollte. Auch diese irrsinnige 30-parametrige Funktion hat für meine Zwecke einen Sinn. Es für mich tatsächlich nötig, 30 Zeiten zusammenzurechnen, und da kommen leicht mal über 100 Stunden als Summe raus, bei denen dann die DateUtils wieder streiken würden. Bingo |
Re: Zeitenberechnungs-Unit, bitte um Tests
Wenn Du mit Zeiten rechnen willst, würde ich von Dezimalzahlen Abstand nehmen! Diese sind zu ungenau.
Ich habe mal eine Zeiterfassungs-Anwendung geschrieben und dabei alles in Minuten umgerechnet und diese als Integer-Wert abgespeichert. Alternativ kann man das auch mit Sekunden so machen. Dann brauchte ich noch vier Funktionen:
Delphi-Quellcode:
Das reicht eigentlich schon aus.
function MinToTime(min: Integer): TTime;
function TimeToMin(t: TTime): Integer; function StrToMin(str: String): Integer; function MinToStr(min: Integer): String; Beispiel:
Delphi-Quellcode:
function MinToTime(min: Integer): TTime;
begin result := EncodeTime(min div 60, min mod 60, 0); end; function TimeToMin(t: TTime): Integer; var h, m, s, ms: Word; begin DecodeTime(t, h, m, s, ms); result := h * 60 + m; end; function MinToStr(min: Integer): String; begin result := Format('%d:%2.2d', [min div 60, min mod 60]); end; |
Re: Zeitenberechnungs-Unit, bitte um Tests
Hallo, habe mir deine Unit angeschaut und meine langjährige Erfahrung sagt mir, dass du völlig auf dem Holzweg bist.
Grundsätzlich gilt: Alle Datums- und Zeitwerte werden zuerst in das interne Format TDateTime umgewandelt. Erst dann werden damit Berechnungen durchgeführt. Mit Strings werden direkt keine Zeitberechnungen durchgeführt. Wenn deine Zeitangaben > als 24 Stunden sind, dann muss man eben Tage hinzunehmen. Du brauchst also nur 2 Funktionen: 1.) einen String (z.B. 50:30:00) nach TDateTime wandeln 2.) einen TDateTime-Wert in einen String wandeln (z.B. 4d 23:50:00 = 4Tage, 23 Std,50 Min) die Funktion zu 1.) könnte so aussehen:
Delphi-Quellcode:
function StrToTimeSpan(timestring: string):TDateTime;
// diese Function parst einen String der Art '25:15:36' // ohne 24 Stunden Grenze der Delphi-eigenen Routinen. var sstd, smin, ssek: string; begin sstd := StrToken(timestr, ':'); smin := StrToken(timestr, ':'); ssek := StrToken(timestr, ':'); hour:= strtointDef(sstd, 0); minute:= strtointDef(smin, 0); sekunde:= strtointDef(ssek, 0); result := (((sekunde / 60.0) + minute) / 60.0 + hour) / 24.0; end;
Delphi-Quellcode:
zu 2.) das bekommst du selbst hin.
// kopiert aus der JCL
function StrToken(var S: string; Separator: Char): string; var I: Integer; begin I := Pos(Separator, S); if I <> 0 then begin Result := Copy(S, 1, I - 1); Delete(S, 1, I); end else begin Result := S; S := ''; end; end; Hinweis: du musst vorher nur die ganzen Tage abtrennen (function frac() und int()), dann kannst du TimeToStr verwenden. |
Re: Zeitenberechnungs-Unit, bitte um Tests
Diese ganzen Gedankengänge hatte ich leider zu meist schon selbst angestellt.
Leider muß ich mit Dezimalzahlen als Zeiten rechnen, da ich teilweise Eingabewerte aus einer bestehenden Exceltabelle auslese und das sind dann leider Dezimalzahlen. Diese rechne ich dann ja so genau es eben möglich ist in einen Zeitwert der Form hh:mm:ss oder hh:mm um, je nachdem wie ich es dann brauche. Auch den Gedanken mit der Tagesabtrennung mußte ich verwerfen, da es sich auf dem 'Lohnzettel' seltsam macht, wenn dann steht: Arbeitszeit: 22d 7h 15min. Deshalb muß alles in Stunden ausgegeben werden, auch wenn es von der Menge her mehrere Tage sind. Ich vermute bisher sehr zu meiner Freude, dass diese Funktionen im allgemeinen scheinbar keine Berechnungsfehler beinhalten, denn sonst hätte das schon einer von euch geschrieben. Mir ist auch klar, dass es vermutlich auch andere, vielleicht elegantere Wege gibt, die für mich erforderlichen Konvertierungen und Berechnungen durchzuführen. Den Vorschlag mit dem Array werde ich noch einmal überdenken, vielleicht spart mir das etwas Schreibarbeit. Bingo |
Re: Zeitenberechnungs-Unit, bitte um Tests
Gerade wenn es sich um Lohnzettel handelt, solltest Du mit Integerwerten rechnen. Die Darstellung als String hhh:mm:ss ist wirklich nur für die Enddarstesllung in der GUI notwendig, alles andere mit Integer rechnen. Dezimalzahlen sind dabei viel zu ungenau (das geht an shmia).
Glaub mir, ich habe das schon alles fertig ;-) |
Re: Zeitenberechnungs-Unit, bitte um Tests
Wenn hier von Dezimalzahl geredet wird, ist dann Dezimalbruch gemeint?
![]() Grüße Klaus |
Re: Zeitenberechnungs-Unit, bitte um Tests
Zitat:
Delphi-Quellcode:
function TimeSpanToStr(timespan:TDateTime);
var Hour, Min, Sec, MSec: Word begin DecodeTime(timespan, Hour, Min, Sec, MSec); // jetzt noch die vollen Tage draufaddieren Hour := Hour + Int(timespan)*24.0; result := Format('%.2d:%.2d:%.2d', [Hour, Min, Sec]); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:44 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