2012-08-27 9 views
5

Sto facendo un lungo ciclo di download di migliaia di file. Vorrei visualizzare un tempo rimanente stimato, poiché potrebbero essere necessarie ore. Tuttavia, con quello che ho scritto, ottengo un numero medio di millisecondi. Come posso convertire questo tempo medio di download da millisecondi a TDateTime?Come convertire i millisecondi in TDateTime?

Vedere dove sto impostando 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 - Sono aperto a diversi modi di calcolare la velocità media degli ultimi download 20 (o AVG_BASE), perché sono sicuro che la mia stringa lista di soluzioni non è la migliore. Non voglio calcolarlo in base a tutti i download, perché la velocità potrebbe cambiare nel tempo. Pertanto, sto solo verificando gli ultimi 20.

risposta

10

Un valore TDateTime è essenzialmente un double, dove la parte intera è il numero di giorni e la frazione è l'ora.

In un giorno ci sono 24 * 60 * 60 = 86400 secondi (SecsPerDay costante dichiarata in SysUtils) in modo da ottenere una come TDateTime fare:

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

Un modo migliore per l'orologio del tempo sarebbe quella di utilizzare il costrutto TStopWatch nell'unità Diagnostics.

Esempio:

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

per ottenere il vostro tempo medio, considerare l'utilizzo di questo record 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 per TStopWatch. Si noti che su alcuni computer, ho scoperto che le funzioni dell'API Win32 di TStopWatch non erano stabili e non funzionavano correttamente (Windows XP, su alcuni chipset Intel Pentium 4 con chipset dell'era ICH4/ICH5). Non è più un problema con l'hardware moderno (Core2Duo e versioni successive), ma ... Ho passato molto tempo a misurare millisecondi (cercando di farlo in modo accurato) e le API di Windows mi hanno dato molto dolore per il tentativo. (Non sto dicendo che voglio un hard realtime, solo un contatore millisecondo che non si blocca o non mi blocca in avanti) - TStopWatch è molto più preciso di GetTickCount! –

+0

+1 anzi, ora se solo potessi prendere in considerazione anche le dimensioni dei file ....... una storia molto diversa però ........ –

8

Invece di un TDateTime è possibile utilizzare il record TTimeSpan, è possibile creare una nuova istanza passando i tick trascorsi allo constructor e da qui è possibile utilizzare i giorni, ore, proprietà di minuti, secondi e millisecondi per visualizzare il tempo trascorso. Ora per calcolare il tempo rimanente sono necessari i byte totali da scaricare e i byte scaricati correnti.

Problemi correlati