![]() |
Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Hallo,
häufig geht man mit Zeiten in Millisekunden um, wie z.B. bei GetTickCount. Um diese übersichtlich darzustellen, habe ich mal eine Funktion geschrieben. Ich bitte um Feedback.
Delphi-Quellcode:
//notwendige Hilfs-Funktionen:
function EndsWith(Text, f: string): boolean; begin Result := False; if Length(Text) < Length(f) then Exit; if CopyL(Text, (Length(Text) - Length(f) + 1), Length(Text)) = f then Result := True; end; function HintenEntfernen(Text, H: string): string; begin Result := Text; if EndsWith(Text, H) then Result := Copy(Text, 1, Length(Text) - Length(H)); end;
Delphi-Quellcode:
Hoffentlich ist alles nachvollziehbar, sonst nachfragen.
function ZeitString(msec: integer): string;
type Einheit = record Bez: string; Mul: integer; Bek: integer; Res: integer; end; const p = ', '; var n: array of Einheit; c: integer = 1; i, j, u, a: integer; procedure SetN(ABez: string; AMul: integer); begin SetLength(n, c + 2); n[c].Bez := ABez; n[c].Mul := AMul; Inc(c); end; begin Result := ''; SetN('ms', 1); SetN('sec', 1000); SetN('min', 60); SetN('hrs', 60); SetN('day', 24); //... j := 1; for i := 0 to High(n) do begin if n[i].Bez = '' then Continue; j := j * n[i].Mul; n[i].Bek := j; end; u := msec; for i := High(n) downto 0 do begin if n[i].Bez = '' then Continue; n[i].Res := u div n[i].Bek; u := u mod n[i].Bek; end; for i := High(n) downto 0 do begin if n[i].Bez = '' then Continue; a := n[i].Res; if (a <> 0) then Result := Result + IntToStr(a) + ' ' + n[i].Bez + p; end; Result := HintenEntfernen(Result, p); end; Grüße |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Delphi-Quellcode:
:gruebel:
function ZeitString(msec: LongWord): string;
var time: TDateTime; s: string; begin //if msec = 0 then Exit('none'); time := msec / MSecsPerDay; if time >= 1 then s := Format(', %d "day"', Trunc(time)); if HourOf(time) <> 0 then s := s + ', h "hrs"'; if MinuteOf(time) <> 0 then s := s + ', m "min"'; if SecondOf(time) <> 0 then s := s + ', s "sec"'; if MilliSecondOf(time) <> 0 then s := s + ', z "ms"'; Result := FormatDateTime(Copy(s, 3), time); end; |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Was verstehst du unter übersichtlich und wie sieht es nachher bei dir aus?
|
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Zitat:
Zitat:
Denn wenn auch nur ein Wert falsch gesetzt ist, dann stimmt die gesammte Berechnung nicht mehr, weswegen man eigentlich nichts auslassen darf. |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Ich meinte thomasschaf.
|
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Der Code von thomasschaf ist zwar allgemeingültig und erweiterbar, aber viel zu komplex, um die einfache Aufgabe (Darstellung von Millisekunden als Tage, Stunden, Minuten etc.) zu lösen. Die Bezeichner sind kryptisch und dienen dazu, den Sinn der Funktion zu verschleiern: Ich verstehe ihn einfach nicht (auf Anhieb).
Himitsu's Code ist schön kompakt und leicht verständlich. Zum Code von thomasschaf: Wenn ich Strings mit einem Trenner konkateniere, mache ich es so:
Delphi-Quellcode:
Die lezte Zeile entspricht deinem 'HintenEntfernen' und ist deutlich kürzer. Ich empfinde bei Code, der erst blind etwas anhängt, um es dann wieder abzuschnippeln, leichtes Unbehagen. Eine Alternative wäre
Const
myDelimiter = ', '; ... MyConcat := ''; For i:=0 to items.Count - 1 do MyConcat := MyConcat+items[i] + myDelimiter; If MyConcat<>'' then setLength(MyConcat, Length (MyConcat) - Length(myDelimiter));
Delphi-Quellcode:
Zur eigentlichen Funktion:
MyConcat := '';
For i:=0 to items.Count - 1 do if MyConcat = '' then MyConcate := items[i] else MyConcat := myDelimiter + MyConcat+items[i]; Die Darstellung der Zeit gefälltt mir nicht (@himitsu: Fühle dich nicht angesprochen). Ich verwende solche formatierten Anzeigen gerne als Countdown, und da sieht es ziemlich blöd aus, wenn die Anzeige in der Länge differiert, nur weil eine Komponente (h,m,s) zufällig mal 0 ist: Ich würde die Komponenten nicht optional angeben, sondern in abhängigkeit von der Größenordnung immer: Liegt der Wert im Bereich von z.B. Minuten, will ich Minuten, Sekunden und Millisekunden anzeigen, also z.B. "1 min, 0 sec, 0 ms". Da ich von Millisekunden ausgehe, will ich auch auf Millisekunden genau anzeigen. Das läßt sich allerdings leicht ändern. Ich würde die Funktion dann so schreiben (ich rechne nicht in TDatetime um, obwohl das bestimmt sinniger wäre):
Delphi-Quellcode:
Bei Zeiten im Millisekundenbereich werden nur die Millisekunden angegeben, bei Zeiten im Sekundenbereich immer Sekunden,Millisekunden usw. Nur bei den Millisekunden sind es derzeit noch konstant drei Stellen
Function MilliSecondsToString (aMilliSecs : Cardinal) : String;
Function AddingTimePortionLeavesZero (aFormat : String; aDivisor : Cardinal) : boolean; begin Result := Result+Format(aFormat, [aMilliSecs mod 1000]); aMilliSecs := aMilliSecs div Divisor; Result := (aMilliSecs=0); End; Begin if aMilliSecs<1000 then begin Result := IntToStr(aMilliSecs); exit; end; Result := ''; If AddingTimePortionLeavesZero('%.3d' , 1000) then exit; If AddingTimePortionLeavesZero('%.2d,', 60) then exit; If AddingTimePortionLeavesZero('%.2d:', 60) then exit; If AddingTimePortionLeavesZero('%.2d' , 24) then exit; if AddingTimePortionLeavesZero('%d d,', 1) then exit; End; |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Hallo,
das Überspringen einer Einheit in der for-Schleife habe ich eingefügt, wenn die Bezeichnung (Bez) der aktuellen Einheit gleich dem leeren String ist. Wenn ich nämlich von 0 nach High(n) durchlaufe ohne die Abfrage, dann ist es mir passiert, dass der erste und letzte n[i].Bez ein leerer String war. Das Ergebnis von dieser Prozedur...
Delphi-Quellcode:
ist
for i := 0 to High(n) do
begin ShowMessage(n[i].Bez); end; '' 'ms' 'sec' 'min' 'hrs' 'day' '' . Ich könnte dann i von 1 bis High(n)-1 durchlaufen lassen, aber die Abfrage dient eher zur Sicherheit (vielleicht ein kleiner Schönheitsfehler). Hier nochmal der Code mitErklärung:
Delphi-Quellcode:
noch ein Beispiel:
function ZeitString(msec: integer): string;
type Einheit = record // definiere einen record beliebiger Einheiten, die sich um Vielfache entsprechen Bez: string; // Name der Einheit Mul: integer; // Faktor zur Vorherigen Einheit (Bsp: Stunde->Tag = 24, weil 24hrs=1day) Bek: integer; // Faktor zur ursprünglichen Einheit (ms). z.B. von Minute ist es 60*1000 Res: integer; // Wie viel in msec von der jeweiligen Einheit drin sind end; const p = ', '; // Trenner zur nächsten Einheit var n: array of Einheit; // Da sind alle Einheiten drin c: integer = 1; // gibt die Größe des Arrays an i, j, u, a: integer; // Hilfsvariablen procedure SetN(ABez: string; AMul: integer); // Hiermit kann man eine neue Einheit hinzufügen begin SetLength(n, c + 2); // Zuerst den Array vergrößeren (das ganz oben genannte Problem könnte auch hierher kommen, weil ich die Länge auf c+2 setze, bei c+1 oder gar c gibts aber Access violation) n[c].Bez := ABez; // einfach die Bezeichnung setzen n[c].Mul := AMul; // und hier den entsprechenden Faktor (Erklärung oben beim record) Inc(c); // für weitere Hinzufügungen um eins vergrößeren, damit die anderen reinpassen end; begin Result := ''; // hier kann man ganz einfach Einheiten hinzufügen, so wie es schon erkannt wurde - ganz toll erweiterbar! SetN('ms', 1); SetN('sec', 1000); SetN('min', 60); SetN('hrs', 60); SetN('day', 24); //... // Zunächst bekommt jeder seinen Faktor zur msec (Bsp sec:1000,min:60*1000,hrs:60*60*1000) // Um diese Multiplikationen hinzubekommen, beziehe ich mich immer wieder auf das vorherige j (Hilfsvar.) j := 1; for i := 0 to High(n) do begin if n[i].Bez = '' then Continue; j := j * n[i].Mul; // hier wird der Faktor zur msec berechnet n[i].Bek := j; // ...und gesetzt end; // u bedeutet "übrig", was also noch vergeben werden muss. // Wenn ich z.B. 9999 habe (in msec natürlich) sind das natürlich 9sek, aber jetzt sind nur noch 999 übrig. u := msec; for i := High(n) downto 0 do // von der größten Einheit beginnen (zuerst also schauen, ob ganze! Tage drin sind) begin if n[i].Bez = '' then Continue; n[i].Res := u div n[i].Bek; // hier kommt die "Res" ins Spiel: div gibt nämlich den Ganzzahl-anteil an u := u mod n[i].Bek; // mit Modulo kriegt man den Rest bei der Division, so kann ich sicherstellen, dass alles richtig verbraucht wird. end; for i := High(n) downto 0 do // jetzt schließlich das Ergebnis ausgeben begin if n[i].Bez = '' then Continue; a := n[i].Res; if (a <> 0) then // genau diese Zeile (Abfrage ob Null-Werte sein sollen) könnte man nach Furtbichler streichen, wenn man es will Result := Result + IntToStr(a) + ' ' + n[i].Bez + p; end; Result := HintenEntfernen(Result, p); // letzte ', ' entfernen. Das war's end;
Delphi-Quellcode:
Hoffentlich ist es jetzt nachvollziehbarer.
ZeitString(1234567890) = 14 day, 6 hrs, 56 min, 7 sec, 890 ms
Grüße |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Zitat:
Bitte so NICHT Software programmieren. Wenn derartige Helper-Funktionen schon so aussehen - also unnötig kompliziert und fünfmal quergedacht - wie sieht dann ein richtiges Programm bei dir aus? |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Auch mit Kommentaren wird ein Programm nicht lesbarer. Guter Code kommt ohne Kommentare aus. Das fängt bei lesbaren und aussagekräftigen Bezeichnern an, wobei die Sprache zweitrangig ist. Es gibt zwar Programmierer, die von deutschen Bezeichnern "Augenkrebs" bekommen, aber dabei frage ich mich immer, wie sie wohl deutsche Straßennamen oder einfach eine deutsche Zeitung lesen.
Kommentare, wie z.B.
Delphi-Quellcode:
dienen ja nicht wirklich der Lesbarkeit, denn wer das ohne Kommentare nicht versteht, wird es auch mit Kommentaren nicht kapieren. Also sind sie an dieser Stelle überflüssig.
For i:=1 to 10 do // hier wird von 1 bis 10 gezählt
Da Du offensichtlich den Code nicht so hinbekommst, wie Du es gerne hättest, sollten wir ihn zunächst entwanzen. Ich schließe dies aus dem Kommentar Zitat:
|
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Delphi-Quellcode:
A: Man kann die Länge auch aus dem Array auslesen, denn das zählt nicht umsonst selber mit.
var
c: integer = 1; // gibt die Größe des Arrays an procedure SetN(ABez: string; AMul: integer); // Hiermit kann man eine neue Einheit hinzufügen begin SetLength(n, c + 2); // Zuerst den Array vergrößeren (das ganz oben genannte Problem könnte auch hierher kommen, weil ich die Länge auf c+2 setze, bei c+1 oder gar c gibts aber Access violation) n[c].Bez := ABez; // einfach die Bezeichnung setzen n[c].Mul := AMul; // und hier den entsprechenden Faktor (Erklärung oben beim record) Inc(c); // B: Dynamische Arrays beginnen bei 0 und nicht 1. Da muß es ja knallen. PS: Debuggen hilft Wunder, man muß es nur nutzen. Und dazu noch in den Projektoptionen die Bereichsprüfung aktivieren, vorallem wenn man des Debuggens nicht mächtig ist. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:53 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 by Thomas Breitkreuz