AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Zeitenberechnungs-Unit, bitte um Tests
Thema durchsuchen
Ansicht
Themen-Optionen

Zeitenberechnungs-Unit, bitte um Tests

Ein Thema von BingoBongo · begonnen am 30. Mai 2007 · letzter Beitrag vom 31. Mai 2007
Antwort Antwort
Seite 1 von 2  1 2      
BingoBongo
Registriert seit: 30. Sep 2005
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
Angehängte Dateien
Dateityp: pas zeitrechnung_121.pas (8,2 KB, 34x aufgerufen)
 
SirTwist

 
Delphi XE Professional
 
#2
  Alt 30. Mai 2007, 12:14
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:
function decintime5: wandelt eine Dezimalzahl in eine Zeit der Form 23:56 um und gibt sie als String zurück
was ist dann mit "eine Dezimalzahl" gemeint? wird 23,5 zu "23:30:00"? oder wird 23,5 zu "00:23:30"?

Um ehrlich zu sein, reicht dafür folgender Fünfzeiler aus:
Delphi-Quellcode:
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;
(runtergetippert, ungetestet).

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:
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;
Der Aufruf erfolgt dann mit AddTimes(["1,5", "2,5", "3,5"]);

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 result:= hour * H + minute * M + sekunde * S; solltest Du besser result := EncodeTime(hour, minute, sekunde); verwenden, da dies genau die dafür vorgesehene Funktion ist.

So, ich hoffe, das hilft Dir ein wenig.
  Mit Zitat antworten Zitat
mkinzler

 
Delphi 11 Alexandria
 
#3
  Alt 30. Mai 2007, 12:23
Und schau dir außerdem mal die Unit DateUtils an.
Markus Kinzler
  Mit Zitat antworten Zitat
BingoBongo
 
#4
  Alt 30. Mai 2007, 13:29
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
  Mit Zitat antworten Zitat
SirTwist

 
Delphi XE Professional
 
#5
  Alt 30. Mai 2007, 13:58
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:
function MinToTime(min: Integer): TTime;
function TimeToMin(t: TTime): Integer;
function StrToMin(str: String): Integer;
function MinToStr(min: Integer): String;
Das reicht eigentlich schon aus.

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;
  Mit Zitat antworten Zitat
shmia

 
Delphi 5 Professional
 
#6
  Alt 30. Mai 2007, 14:12
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:
// 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;
zu 2.) das bekommst du selbst hin.
Hinweis: du musst vorher nur die ganzen Tage abtrennen (function frac() und int()), dann kannst du TimeToStr verwenden.
Andreas
  Mit Zitat antworten Zitat
BingoBongo
 
#7
  Alt 30. Mai 2007, 14:26
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
  Mit Zitat antworten Zitat
SirTwist

 
Delphi XE Professional
 
#8
  Alt 30. Mai 2007, 14:34
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
  Mit Zitat antworten Zitat
Klaus01

 
Delphi 10.4 Sydney
 
#9
  Alt 30. Mai 2007, 14:38
Wenn hier von Dezimalzahl geredet wird, ist dann Dezimalbruch gemeint?
Info DezimalSystem

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
shmia

 
Delphi 5 Professional
 
#10
  Alt 30. Mai 2007, 14:53
Zitat von BingoBongo:
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.
Auch das ist kein Problem:
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;
Andreas
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 06:03 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz