AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

Ein Thema von thomasschaf · begonnen am 26. Mär 2012 · letzter Beitrag vom 27. Mär 2012
Antwort Antwort
Seite 1 von 2  1 2   
thomasschaf
(Gast)

n/a Beiträge
 
#1

Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 00:26
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:
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;
Hoffentlich ist alles nachvollziehbar, sonst nachfragen.

Grüße
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
40.509 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 00:57
Delphi-Quellcode:
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;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list

Geändert von himitsu (26. Mär 2012 um 01:11 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie
(Moderator)

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#3

AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 00:58
Was verstehst du unter übersichtlich und wie sieht es nachher bei dir aus?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
40.509 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 01:17
Was verstehst du unter übersichtlich und wie sieht es nachher bei dir aus?
Mein Code sollte genau das Selbe machen ... ist es aus Diesem nicht ersichtlich, was raus kommt?
Zitat:
Delphi-Quellcode:
    if n[i].Bez = 'then
      Continue;
Das versteh ich aber nicht.

Denn wenn auch nur ein Wert falsch gesetzt ist, dann stimmt die gesammte Berechnung nicht mehr, weswegen man eigentlich nichts auslassen darf.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie
(Moderator)

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#5

AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 01:26
Ich meinte thomasschaf.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#6

AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 08:00
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:
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));
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
Delphi-Quellcode:
MyConcat := '';
For i:=0 to items.Count - 1 do
  if MyConcat = 'then
    MyConcate := items[i]
  else
    MyConcat := myDelimiter + MyConcat+items[i];
Zur eigentlichen Funktion:
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:
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;
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

Geändert von Furtbichler (26. Mär 2012 um 08:17 Uhr)
  Mit Zitat antworten Zitat
thomasschaf
(Gast)

n/a Beiträge
 
#7

AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 13:09
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:
  for i := 0 to High(n) do
  begin
    ShowMessage(n[i].Bez);
  end;
ist

''
'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:
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;
noch ein Beispiel:
ZeitString(1234567890) = 14 day, 6 hrs, 56 min, 7 sec, 890 ms Hoffentlich ist es jetzt nachvollziehbarer.

Grüße
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
2.973 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 20:11
ZeitString(1234567890) = 14 day, 6 hrs, 56 min, 7 sec, 890 ms Hoffentlich ist es jetzt nachvollziehbarer.
Nichtsdestotrotz ist das schlimmer Augenkrebs.
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?
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#9

AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 21:58
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. For i:=1 to 10 do // hier wird von 1 bis 10 gezählt 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.

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 von einem Kommentar in deinem Code:
...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
.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
40.509 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: Vorstellung des Codes zur übersichtlichen Anzeige von Zeiten

  Alt 26. Mär 2012, 22:11
Delphi-Quellcode:
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); //
A: Man kann die Länge auch aus dem Array auslesen, denn das zählt nicht umsonst selber mit.

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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:12 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf