Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I convert milliseconds to a TDateTime?

I'm doing a long loop downloading thousands of files. I would like to display an estimated time remaining, since it could take hours. However, with what I've written, I get an average number of milliseconds. How do I convert this average download time from milliseconds to a TDateTime?

See where I'm setting 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 - I'm open to different ways of calculating the average speed of the last 20 (or AVG_BASE) downloads, because I'm sure my string list solution isn't the best. I don't want to calculate it based on all downloads, because speed may change over that time. Therefore, I'm just checking the last 20.

like image 932
Jerry Dodge Avatar asked Aug 27 '12 01:08

Jerry Dodge


People also ask

How do you convert milliseconds to dates?

This is the number of seconds since the 1970 epoch. To convert seconds to milliseconds, you need to multiply the number of seconds by 1000. To convert a Date to milliseconds, you could just call timeIntervalSince1970 and multiply it by 1000 every time.

How do you convert milliseconds to seconds minutes and hours?

To convert milliseconds to hours, minutes, seconds:Divide the milliseconds by 1000 to get the seconds. Divide the seconds by 60 to get the minutes. Divide the minutes by 60 to get the hours. Add a leading zero if the values are less than 10 to format them consistently.

What is milliseconds equal to?

A millisecond (from milli- and second; symbol: ms) is a unit of time in the International System of Units (SI) equal to one thousandth (0.001 or 10−3 or 1/1000) of a second and to 1000 microseconds.

How do you convert milliseconds ms into seconds?

One millisecond is equal to 1 × 10-3 to unit of time second. Therefore 1 millisecond = 0.001 seconds.


2 Answers

A TDateTime value is essentially a double, where the integer part is the number of days and fraction is the time.

In a day there are 24*60*60 = 86400 seconds (SecsPerDay constant declared in SysUtils) so to get A as TDateTime do:

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

A better way to clock the time would be to use the TStopWatch construct in the unit Diagnostics.

Example:

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

To get your average time, consider using this moving average record:

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;
like image 116
LU RD Avatar answered Oct 04 '22 00:10

LU RD


Instead of a TDateTime you can use the TTimeSpan record, you can create a new instance passing the ticks elapsed to the constructor and from here you can use the Days, Hours, minutes, seconds and Milliseconds properties to display the elapsed time. Now for calculate the remaining time you need the total bytes to download and the current downloaded bytes.

like image 34
RRUZ Avatar answered Oct 04 '22 00:10

RRUZ