2012-08-27 48 views
5

我正在做一個長循環下載數千個文件。我想顯示剩餘的估計時間,因爲它可能需要幾小時。然而,用我寫的,我得到的平均數爲毫秒。如何將平均下載時間從毫秒轉換爲TDateTime如何將毫秒轉換爲TDateTime?

看到我設置Label1.Caption

procedure DoWork; 
const 
    AVG_BASE = 20; //recent files to record for average, could be tweaked 
var 
    Avg: TStringList; //for calculating average 
    X, Y: Integer; //loop iterators 
    TS, TE: DWORD; //tick counts 
    A: Integer; //for calculating average 
begin 
    Avg:= TStringList.Create; 
    try 
    for X:= 0 to FilesToDownload.Count - 1 do begin //iterate through downloads 
     if FStopDownload then Break; //for cancelling 
     if Avg.Count >= AVG_BASE then //if list count is 20 
     Avg.Delete(0); //remove the oldest average 
     TS:= GetTickCount; //get time started 
     try 
     DownloadTheFile(X); //actual file download process 
     finally 
     TE:= GetTickCount - TS; //get time elapsed 
     end; 
     Avg.Add(IntToStr(TE)); //add download time to average list 
     A:= 0; //reset average to 0 
     for Y:= 0 to Avg.Count - 1 do //iterate through average list 
     A:= A + StrToIntDef(Avg[Y], 0); //add to total download time 
     A:= A div Avg.Count; //divide count to get average download time 
     Label1.Caption:= IntToStr(A); //<-- How to convert to TDateTime? 
    end; 
    finally 
    Avg.Free; 
    end; 
end; 

PS - 我願意計算在過去的20(或AVG_BASE)下載的平均速度不同的方式,因爲我相信我的字符串列表解決方案不是最好的。我不想根據所有下載來計算它,因爲速度可能會隨着時間而改變。因此,我只是檢查最後20個。

回答

10

TDateTime值本質上是一個double,其中整數部分是天數,分數是時間。

一天有24 * 60 * 60 = 86400秒(SecsPerDay常數SysUtils單元聲明),以便獲得一個爲TDateTime類型做:

dt := A/(SecsPerDay*1000.0); // A is the number of milliseconds 

時鐘一個更好的辦法的時候是使用在單元Diagnostics中的TStopWatch結構。

例子:

sw.Create; 
.. 
sw.Start; 
// Do something 
sw.Stop; 
A := sw.ElapsedMilliSeconds; 
// or as RRUZ suggested ts := sw.Elapsed; to get the TimeSpan 

爲了讓您的平均時間,可以考慮使用此moving average記錄:

Type 
    TMovingAverage = record 
    private 
    FData: array of integer; 
    FSum: integer; 
    FCurrentAverage: integer; 
    FAddIx: integer; 
    FAddedValues: integer; 
    public 
    constructor Create(length: integer); 
    procedure Add(newValue: integer); 
    function Average : Integer; 
    end; 

procedure TMovingAverage.Add(newValue: integer); 
var i : integer; 
begin 
    FSum := FSum + newValue - FData[FAddIx]; 
    FData[FAddIx] := newValue; 
    FAddIx := (FAddIx + 1) mod Length(FData); 
    if (FAddedValues < Length(FData)) then 
    Inc(FAddedValues); 
    FCurrentAverage := FSum div FAddedValues; 
end; 

function TMovingAverage.Average: Integer; 
begin 
    Result := FCurrentAverage; 
end; 

constructor TMovingAverage.Create(length: integer); 
var 
    i : integer; 
begin 
    SetLength(FData,length); 
    for i := 0 to length - 1 do 
    FData[i] := 0; 
    FSum := 0; 
    FCurrentAverage := 0; 
    FAddIx := 0; 
    FAddedValues := 0; 
end; 
+1

+1 TStopWatch。請注意,在某些計算機上,我發現TStopWatch的底層Win32 API函數不穩定並且無法正常工作(Windows XP,某些採用ICH4/ICH5時代芯片組的Intel Pentium 4芯片組)。在現代硬件上(Core2Duo和更高版本)不再是問題,但是......我花了很多時間測量毫秒(準確地做到這一點),Windows API讓我非常難受。 (我並不是說我想要實時,只需要一個毫秒級的計數器,它不會在我身上停滯不前) - TStopWatch比GetTickCount準確得多! –

+0

+1確實,現在如果只有我可以考慮文件大小......儘管.......完全不同的故事........ –

8

可以使用TTimeSpan記錄代替TDateTime創建一個新實例,將經過的刻度傳遞給constructor,並從這裏您可以使用Days,Hours,分鐘,秒和毫秒屬性顯示已用時間。現在計算剩餘時間,您需要下載總字節數和當前下載的字節數。