2011-11-22 77 views
4

我正在建立一个倒计时到某个日期/时间的东西。我有它的工作 - 至少小时,分钟和秒工作正常。我的问题是当我尝试实施天时,它没有给出正确的结果。我知道DateUtils的单元,但那里有很多东西,我不知道该怎么做,特别是因为我数学很糟糕。日期/时间操纵友好的倒计时字符串

我有一个间隔为100的计时器。然后我有一个全球的fDestDT为目标日期/时间倒计时的基础。在计时器中,我有一个名为DT的本地TDateTime。然后,我打破它分为多个字符串,并把他们重新走到一起进1“友好”串...

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; 

应该出来像...

0 Days, 3 Hours, 1 Minute, 12 Seconds

但相反的日子都出现了错误,当倒计时的日期/时间是今天的日期,它显示30天......

30 Days, 3 Hours, 1 Minute, 12 Seconds

我想,如果我提前一个多月,它也不会正确显示。我如何正确获取天数? DateUtils单元中有没有什么能比我已经更好地自动化大部分工作?编辑: 固定!问题是我很愚蠢地用DT:= fDestDT - Now;减去,这在我的第一个代码片段中是正确的,但是在转换为使用DateUtils.DaysBetween代替之后,我需要删除该减法,并且仅设置DT:= Now;

工作代码:

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; 

回答

7

DaysBetweenHoursBetweenMinutesBetween,并且SecondsBetweenDateUtils 。你必须做一些小数学。 :)

下面是一个示例控制台应用程序演示:

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. 

产生以下输出:

Time differences

注意参数顺序的DaysBetweenHoursBetween之间的逆转是故意的证明这些函数总是返回正值,所以参数的顺序并不重要。这在文档中提到。

+0

我在这里得到错误的秒数...把它放在一个计时器中,并实时观察输出 - 你会发现它不太正确,秒钟总是出现在30秒以内。 –

+0

是的,秒和分钟应该是'mod 60'而不是'mod 24' –

+0

已经完成了。发布最后评论时必定发生。 :) –

4

的问题是,当你从fDestDT减去Now你希望两个日期之间获得的区别,但实际上你得到另一个datetime值。由于您使用的值几乎相同,因此您可以得到德尔福的datetime系统的“零日期”,即30.分钟1899.这就是为什么您会得到FormatDateTime('d', DT)+' Days'的“30天”。

以来的最小量的youre在intrested是第二,我建议你使用SecondsBetween获得两个时间戳之间的差别,然后将其分成几部分像

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'; 
+0

谢谢,但从那时起问题就被修改了,现在正在使用一种不同的方法来使用DateUtils。 +1的答案虽然。 –

+0

+1为解释为什么OP是30天。 –

3

如果您使用的是Delphi 2010(我相信)或以上版本,您可能会简化您的代码,并使用TimeSpan.pas单位更清晰,该单位包含一条记录,您可以使用该记录来分析给定的时间跨度。

+0

不,我有德尔福7,但有什么办法可以潜入这个TimeSpan.pas单位吗?听起来像它正是我所需要的... –

+0

尼克,标签说Delphi 7。:)杰里,你可以通过升级你的Delphi副本来获得'TimeSpan'。 ;) –

+1

我已经使用2010年,我仍然喜欢7:PI猜我会去得到一个该单位的副本,并为德尔福7:D –