2012-08-27 33 views
5

Estoy haciendo un ciclo largo descargando miles de archivos. Me gustaría mostrar un tiempo restante estimado, ya que podría llevar horas. Sin embargo, con lo que he escrito, obtengo un número promedio de milisegundos. ¿Cómo convierto este tiempo promedio de descarga de milisegundos a TDateTime?¿Cómo convierto milisegundos a TDateTime?

ver donde estoy estableciendo 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 - Estoy abierto a diferentes formas de calcular la velocidad media de los últimos 20 descargas (o AVG_BASE), porque estoy seguro de que mi cadena la lista de soluciones no es la mejor. No quiero calcularlo en base a todas las descargas, porque la velocidad puede cambiar durante ese tiempo. Por lo tanto, solo estoy verificando los últimos 20.

Respuesta

10

Un valor de TDateTime es esencialmente un double, donde la parte entera es el número de días y la fracción es el tiempo.

En un día hay (declarado SecsPerDay constante en SysUtils) 24 * 60 * 60 = 86400 segundos para llegar A como TDateTime hacer:

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

Una mejor forma de reloj de la hora sería utilizar la construcción TStopWatch en la unidad Diagnostics.

Ejemplo:

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

para obtener su promedio de tiempo, considerar el uso de este registro 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 para TStopWatch. Tenga en cuenta que en algunas computadoras, encontré que las funciones API de Win32 subyacentes de TStopWatch no eran estables y no funcionaban correctamente (Windows XP, en ciertos conjuntos de chips Intel Pentium 4 con conjuntos de chips de la era ICH4/ICH5). Ya no es un problema en el hardware moderno (Core2Duo y posterior), pero ... He pasado mucho tiempo midiendo milisegundos (tratando de hacerlo con precisión) y las API de Windows me han dado mucha pena por intentarlo. (No estoy diciendo que quiera un tiempo real difícil, solo un contador de milisegundos que no se congela ni se lanza hacia mí) - ¡TStopWatch es mucho más preciso que GetTickCount! –

+0

+1 de hecho, ahora si solo pudiera tomar en consideración el tamaño de los archivos ....... aunque sea una historia diferente ........ –

8

En lugar de un TDateTime puede usar el registro TTimeSpan, puede crear una nueva instancia pasando los ticks transcurridos al constructor y desde aquí puede usar los días, las horas, minutos, segundos y propiedades Milisegundos para mostrar el tiempo transcurrido. Ahora, para calcular el tiempo restante, necesita el total de bytes para descargar y los bytes descargados actuales.

Cuestiones relacionadas