Date / Time Manipulation - freundlicher Countdown-String

  • 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;
     
    22 November 2011
    Jerry Dodge
3 answers
  • 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:

    Date / Time Manipulation - freundlicher Countdown-String

    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.

    25 November 2011
    Ken White
  • 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';
     
    22 November 2011
    ainreckface
  • 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.

    22 November 2011
    Nick Hodges