![]() |
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. |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Zitat:
Ein derartiges Desperanto hat in diesem Kontext (Programmierung & Quelltextgestaltung) nichts verloren. Der Vergleich zu einer deutschen Zeitung mit deutschen Wörtern in deutschen Sätzen...oder um es kurz zu sagen: in deutscher Sprache...ist hier fehl am Platz und fordert geradezu die berühmte Äpfel/Birnen-Metapher. |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Zitat:
Deutsche Nomenklatur ist unter erfahrenen Programmierern, zumindest in meinem Umfeld (>10-20 Jahre Praxis) akzeptiert und wird gefördert. Es ist immer noch besser, als schlechte englische Bezeichner, aus dict.leo.org zusammengeklaubt und damit häufig falsch und irreführend. Im internationalen Teams ist das natürlich fehl am Platz: Dort gilt das Gesetz der Mehrheit (und nicht: English or Die). Im aktuellen Team aus 30 Steuerungsprogrammierern ist deutsch jedenfalls Standard. Im letzten Team war es (logischerweise) englisch. Wenn die von dir ziemlich isoliert bezeichnete "Desperanto"-Nomenklatur auch zu Augenkrebs führt, dann geh zum Augenarzt. |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Zitat:
Zitat:
Wie du selber weiter unten richtig bemerkst, geht das ab einen gewissen Professionalitätsniveau einfach nicht. Ich weiß nicht in was für Arten von Firmen die meisten hier arbeiten und Software entwicklen. Darüber will ich mir auch kein Urteil erlauben. Manchmal kommt der Eindruck auf, dass die meisten nur Datenbankkomponenten auf Forms schieben und bissel Zauberpulver darüber streuen oder nichts weiter tun als Strings auseinander und zusammenzuwürfeln, aber na ja... In Zeiten von internationalen Teams, ausländischen Tochterfirmen mit eignen Entwicklern und nichtdeutschen SDK-Anwendern/Kunden kann man Sachen wie "ZahlVonLinks" oder "ZahlVonRechts" nicht bringen. Klar ist es oft einfacher und schneller, weil intuitiver, deutsche Bezeichner zu verwenden. Aber spätestens wenn das Modul abgeschlossen ist und alles zufriedenstellend funktioniert, sollte man per Refactoring das Ganze bearbeiten. Wenn in fünf Jahren der franzöische Kollege, der indische Programmierer (der per Outsourcing deinen deutschen Gulasch lesen muss) oder der kalifornische Kunde etwas damit anzufangen will, sollte das ohne Wörterbuch gehen. Denn dann bist du schon lange nicht mehr für diesen Quelltext verantwortlich, entweder weil hast du die Firma verlassen hast oder die Karriereleiter hochgefallen bist. Es ist einfach eine Frage der Höflichkeit. Zitat:
Auch ich bin keiner der von sich sagt, dass er problemlos in allen Lebenssituationen mit einen native speaker mithalten kann, aber ich kann zumindest versuchen halbwegs passende Bezeichner zu wählen. Ich denke, dass nichtdeutschsprachige Kollegen eher ein "NumberFromLeft" interpretieren können als ein "ZahlVonLinks". Je eher man sich daran gewöhnt, desto geringer fällt die Umgewöhnung aus, wenn es wirklich gefordert ist. Ich gebe aber zu meine Quelltexte mit englischen Wörtern zu gestalten, aber ab und zu auch mal Kommentare in deutsch zu schreiben. Dass dann aber bewusst aus Faulheit und Bequemlichkeit. |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Zitat:
Leider bewahrheitet sich diese Vermutung auch bei etwas über 90% aller Bewerbungen, die bei mir auf dem Schreibtisch landen... |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Deutsch:
![]() Wenn alle in der Firma mitmachen, würde ich darin kein Hindernis sehn. (Hat den Vorteil, daß die I... von der Cheffabteilung auch mal ein Bissl was verstehen könnten) OK, schlimmer ist es, wenn ich mir chinesische oder russische Codes anguck. |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Warum muss so eine Diskussion nur immer ins Persönliche abgleiten? *seufz* Könnt ihr euch nicht mal am Riemen reißen und sachlich über einen Code diskutieren? :warn:
Und außerdem geht es hier nicht um die Sprache der Bezeichner oder Kommentare. |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Zitat:
b) Steht es dir frei diese Diskussion als eigenen Thread abzutrennen. |
AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten
Na, wer die Aussagen eines anderen als absoluten Blödsinn hinstellt, ist schon persönlich.
Aber das gilt ja für euch beide. Ich für meinen Teil halte es so: 1. Übersichtlich und lesbar. 2. if (1) trifft not zu, Goto 1 3. Wenn man hierhin kommt, bitte in Englisch Ich glaube, alle vernünftigen Programmierer denken so. Bezüglich des Codes von thomasschaf ist das Wesentliche gesagt: 1. (-) Sehr kompliziert und zu komplex für die Aufgabe 2. (+) Vom Versuch her allgemeingültig 3. (-) Keine aussagekräftigen Bezeichner 4. (-) Fehlerhafter Code der nur notdürftig geflickt wurde Da zu allen Punkten etwas gesagt wurde, denke ich, wir geben ihm Zeit, die Sachen umzusetzen, wenn er möchte. Uns sollten wir Zeit geben, das Wetter zu genießen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:32 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