Ich baue etwas, das bis zu einem bestimmten Zeitpunkt einen Countdown hat. Ich habe es funktioniert - zumindest die Stunden, Minuten und Sekunden funktionieren gut. Mein Problem ist, wenn ich versuche, Days zu implementieren, gibt es nicht das richtige Ergebnis. Ich weiß über DateUtils Bescheid, aber es gibt so viel Zeug und ich weiß nicht, wie ich das machen soll, zumal ich in Mathe schrecklich bin.
Ich habe einen Timer mit Intervall bei 100. Dann habe ich ein globales fDestDT
für das Datum und die Uhrzeit des Ziels, um den Countdown abzugrenzen. Im Timer habe ich eine lokale TDateTime namens DT
. Ich zerlege sie dann in mehrere Zeichenfolgen und füge sie wieder zu einer "freundlichen" Zeichenfolge zusammen ...
procedure TForm1.TmrTimer(Sender: TObject);
var
DT: TDateTime;
D, H, N, S: String;
Str: String;
begin
DT:= fDestDT - Now; //fDest = destination date/time of countdown
//Need to format only plural numbers with 's'
D:= FormatDateTime('d', DT)+' Days'; //Get number of days
H:= FormatDateTime('h', DT)+' Hours'; //Get number of hours
N:= FormatDateTime('n', DT)+' Minutes'; //Get number of minutes
S:= FormatDateTime('s', DT)+' Seconds'; //Get number of seconds
Str:= D+', '+H+', '+N+', '+S; //Build friendly string
if lblTitle.Caption <> Str then
lblTitle.Caption:= Str; //Update caption only if it's changed
end;
Es sollte etwas herauskommen wie ...
0 Days, 3 Hours, 1 Minute, 12 Seconds
Stattdessen zeigen die Tage falsch, wenn das Datum / Der Countdown ist auf dem heutigen Datum, es zeigt 30 Tage ...
30 Days, 3 Hours, 1 Minute, 12 Seconds
Ich gehe davon aus, dass Ich sollte es mehr als 1 Monat im Voraus einstellen, es würde auch nicht richtig angezeigt. Wie bekomme ich die Anzahl der Tage richtig? Und gibt es etwas in der DateUtils-Einheit, das die meisten dieser Aufgaben besser automatisieren kann als ich es bereits bin?
BEARBEITEN:
BEHOBEN! Das Problem war, dass ich dumm mit DT:= fDestDT - Now;
subtrahierte, was in meinem ersten Code-Snippet richtig war, aber nach der Konvertierung in DateUtils.DaysBetween
musste ich diese Subtraktion entfernen und einfach DT:= Now;
setzen.
Arbeitscode:
procedure TForm1.TmrTimer(Sender: TObject);
var
DT: TDateTime;
Days, Hours, Mins, Secs: Word;
SDays, SHours, SMins, SSecs: String;
Str: String;
begin
DT:= Now;
Days:= DaysBetween(DT, fDestDT);
Hours:= HoursBetween(fDestDT, DT) mod 24; // Remove total days
Mins:= MinutesBetween(DT, fDestDT) mod 60;
Secs := SecondsBetween(DT, fDestDT) mod 60;
if Days = 1 then SDays:= 'Day' else SDays:= 'Days';
if Hours = 1 then SHours:= 'Hour' else SHours:= 'Hours';
if Mins = 1 then SMins:= 'Minute' else SMins:= 'Minutes';
if Secs = 1 then SSecs:= 'Second' else SSecs:= 'Seconds';
Str:= Format('%d '+SDays+' %d '+SHours+' %d '+SMins+' %d '+SSecs,
[Days, Hours, Mins, Secs]);
if lblTime.Caption <> Str then
lblTime.Caption:= Str;
end;
Siehe DaysBetween
, HoursBetween
, MinutesBetween
und SecondsBetween
in DateUtils
. Du musst ein paar kleine Berechnungen machen. :)
Hier sehen Sie eine Beispielkonsolen-App:
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils, DateUtils;
procedure ShowTimeDiff(const StartDate, OldDate: TDateTime);
var
Days, Hours, Mins, Secs: Word;
OutputText: string;
begin
Writeln(Format('Start: %s, Old: %s',
[FormatDateTime('mm/dd/yyyy hh:nn:ss', StartDate),
FormatDateTime('mm/dd/yyyy hh:nn:ss', OldDate)]));
Days := DaysBetween(StartDate, OldDate);
Hours := HoursBetween(OldDate, StartDate) mod 24; // Remove total days
Mins := MinutesBetween(StartDate, OldDate) mod 60;
Secs := SecondsBetween(StartDate, OldDate) mod 60;
OutputText := Format(' %d days, %d hours, %d min, %d secs',
[Days, Hours, Mins, Secs]);
WriteLn(OutputText);
end;
var
BeginDate, EndDate: TDateTime;
begin
BeginDate := Now;
EndDate := BeginDate - 0.5; // about 12 hours earlier
ShowTimeDiff(BeginDate, EndDate);
EndDate := BeginDate - 2.53724; // Create date about 2 1/2 days earlier
ShowTimeDiff(EndDate, BeginDate);
EndDate := BeginDate - 5.75724; // Create date about 5 3/4 days earlier
ShowTimeDiff(BeginDate, EndDate);
ReadLn;
end.
Erzeugt die folgende Ausgabe:
Beachten Sie, dass die Umkehrung der Parameterreihenfolge zwischen DaysBetween
und HoursBetween
beabsichtigt zu zeigen, dass die Funktionen immer positive Werte zurückgeben, daher ist die Reihenfolge der Parameter nicht wichtig. Dies ist in der Dokumentation erwähnt.
Das Problem ist, dass, wenn Sie Now
von fDestDT
subtrahieren, erwarten Sie eine Differenz zwischen zwei Datumsangaben, tatsächlich jedoch einen anderen datetime-Wert. Da die Werte, die Sie verwenden, nahezu gleich sind, erhalten Sie das "Nulldatum" der des Delphi System, das 30. dets 1899. Deshalb erhalten Sie "30 Tage" für FormatDateTime('d', DT)+' Days'
.
Da die geringste Menge, die Sie interessieren, an zweiter Stelle ist, schlage ich Sie vor Verwenden Sie SecondsBetween , um die Differenz zwischen zwei Zeitstempeln zu ermitteln und sie in Teile aufzuteilen wie
diff := SecondsBetween(Now, fDestDT);
S:= IntToStr(diff mod 60)+' Seconds';
diff := diff div 60;
N:= IntToStr(diff mod 60)+' Minutes';
diff := diff div 60;
H:= IntToStr(diff mod 24)+' Hours';
diff := diff div 24;
D:= IntToStr(diff)+' Days';
Wenn Sie Delphi 2010 (glaube ich) oder höher verwenden, können Sie Ihren Code wahrscheinlich vereinfachen und klarer machen, indem Sie die Einheit TimeSpan.pas
verwenden, die einen Datensatz enthält, mit dem Sie den Code ausbrechen können Zeitdauer in einer bestimmten Zeitspanne.