Переглянути джерело

Quick.Chrono microsecond and nanosecond precission

Class internal refactory
Exilon 7 роки тому
батько
коміт
d864da599d
1 змінених файлів з 66 додано та 89 видалено
  1. 66 89
      Quick.Chrono.pas

+ 66 - 89
Quick.Chrono.pas

@@ -1,13 +1,13 @@
-{ ***************************************************************************
+{ ***************************************************************************
 
-  Copyright (c) 2015-2018 Kike Pérez
+  Copyright (c) 2015-2018 Kike Pérez
 
   Unit        : Quick.Chrono
   Description : Chronometers time elapsed and estimated time to do a task
-  Author      : Kike Pérez
+  Author      : Kike Pérez
   Version     : 1.2
   Created     : 27/08/2015
-  Modified    : 27/02/2018
+  Modified    : 02/03/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -43,6 +43,8 @@ resourcestring
   strMINUTE = 'minute';
   strSECOND = 'second';
   strMILLISECOND = 'millisecond';
+  strMICROSECOND = 'microsecond';
+  strNANOSECOND = 'nanosecond';
   strFMTSHORT_HOURS_MINUTES = 'hh:nn:ss';
   strFMTSHORT_MINUTES_SECONDS = 'hh:nn:ss';
   strFMTLONG_HOURS_MINUTES = 'h "hour(s) and" n "minute(s)"';
@@ -50,12 +52,13 @@ resourcestring
 
 type
 
-  TTimeValue = (utDay, utHour, utMinute, utSecond, utMillisecond);
+  TTimeValue = (utDay, utHour, utMinute, utSecond, utMillisecond,utMicrosecond,utNanosecond);
   TTimeFmt = (tfHoursAndMinutes, tfMinutesAndSeconds);
+  TPrecissionFormat = (pfFloat, pfRound, pfTruncate);
 
 const
-  UnitShortTime : array[utDay..utMillisecond] of string = ('d','h','m','s','ms');
-  UnitLongTime : array[utDay..utMillisecond] of string = (strDAY,strHOUR,strMINUTE,strSECOND,strMILLISECOND);
+  UnitShortTime : array[utDay..utNanosecond] of string = ('d','h','m','s','ms','μs','ns');
+  UnitLongTime : array[utDay..utNanosecond] of string = (strDAY,strHOUR,strMINUTE,strSECOND,strMILLISECOND,strMICROSECOND,strNANOSECOND);
   FmtShortTime : array[tfHoursAndMinutes..tfMinutesAndSeconds] of string = (strFMTSHORT_HOURS_MINUTES,strFMTSHORT_MINUTES_SECONDS);
   FmtLongTime : array[tfHoursAndMinutes..tfMinutesAndSeconds] of string = (strFMTLONG_HOURS_MINUTES,strFMTLONG_MINUTES_SECONDS);
 
@@ -64,11 +67,13 @@ type
   TChronometer = class
   private
     fFrequency: TLargeInteger;
+    fUnitsPerMiS : Int64;
     fIsRunning: Boolean;
     fIsHighResolution: Boolean;
     fStartCount, fStopCount: TLargeInteger;
     fStartBreakPoint, fStopBreakPoint : TLargeInteger;
-    fReportFormatPrecission : Boolean;
+    fReportFormatPrecission : TPrecissionFormat;
+    class function Precission(aValue : Extended; FormatPrecission : TPrecissionFormat) : Extended;
     procedure SetTickStamp(var lInt: TLargeInteger);
     function GetElapsedTicks: TLargeInteger;
     function GetElapsedMilliseconds: TLargeInteger;
@@ -87,7 +92,7 @@ type
     procedure BreakPoint;
     property IsHighResolution: Boolean read fIsHighResolution;
     property IsRunning: Boolean read fIsRunning;
-    property ReportFormatPrecission: boolean read fReportFormatPrecission write fReportFormatPrecission;
+    property ReportFormatPrecission: TPrecissionFormat read fReportFormatPrecission write fReportFormatPrecission;
     property ElapsedTicks: TLargeInteger read GetElapsedTicks;
     property ElapsedMilliseconds: TLargeInteger read GetElapsedMilliseconds;
     property ElapsedMilliseconds_Breakpoint: TLargeInteger read GetElapsedMilliseconds_BreakPoint;
@@ -97,7 +102,7 @@ type
     function ElapsedTime(LongFormat : Boolean = False) : string;
     function ElapsedTime_BreakPoint(LongFormat : Boolean = False) : string;
     class function MillisecondsToString(aMilliseconds : TLargeInteger; LongFormat : Boolean = False) : string; overload;
-    class function MillisecondsToString(aMillisecondsWithPrecission : Extended; LongFormat : Boolean = False) : string; overload;
+    class function MillisecondsToString(aMilliseconds : Extended; FormatPrecission : TPrecissionFormat = pfFloat; LongFormat : Boolean = False) : string; overload;
 
   end;
 
@@ -133,12 +138,13 @@ begin
   inherited Create;
   fIsRunning := False;
   fIsHighResolution := QueryPerformanceFrequency(fFrequency);
-  fReportFormatPrecission := True;
+  fReportFormatPrecission := pfFloat;
   fStartCount := 0;
   fStopCount := 0;
   fStartBreakPoint := 0;
   fStopBreakPoint := 0;
   if not fIsHighResolution then fFrequency := MSecsPerSec;
+  fUnitsPerMiS := fFrequency div 1000000;
   if StartOnCreate then Start;
 end;
 
@@ -155,30 +161,12 @@ end;
 
 function TChronometer.ElapsedTime(LongFormat : Boolean = False) : string;
 begin
-  if LongFormat then
-  begin
-    if fReportFormatPrecission then Result := MillisecondsToString(ElapsedMillisecondsWithPrecission,True)
-      else Result := MillisecondsToString(ElapsedMilliseconds,True);
-  end
-  else
-  begin
-    if fReportFormatPrecission then Result := MillisecondsToString(ElapsedMillisecondsWithPrecission)
-      else Result := MillisecondsToString(ElapsedMilliseconds);
-  end;
+  Result := MillisecondsToString(ElapsedMillisecondsWithPrecission,fReportFormatPrecission,LongFormat);
 end;
 
 function TChronometer.ElapsedTime_BreakPoint(LongFormat : Boolean = False) : string;
 begin
-  if LongFormat then
-  begin
-    if fReportFormatPrecission then Result := MillisecondsToString(ElapsedMillisecondsWithPrecission_BreakPoint,True)
-      else Result := MillisecondsToString(ElapsedMilliseconds_BreakPoint,True);
-  end
-  else
-  begin
-    if fReportFormatPrecission then Result := MillisecondsToString(ElapsedMillisecondsWithPrecission_BreakPoint)
-      else Result := MillisecondsToString(ElapsedMilliseconds_BreakPoint);
-  end;
+  Result := MillisecondsToString(ElapsedMillisecondsWithPrecission_BreakPoint,fReportFormatPrecission,True);
 end;
 
 class function TChronometer.GetUnitTime(TimeValue : TTimeValue; LongFormat : Boolean) : string;
@@ -194,79 +182,68 @@ begin
 end;
 
 class function TChronometer.MillisecondsToString(aMilliseconds : TLargeInteger; LongFormat : Boolean = False) : string;
-var
-  dt : TDateTime;
-  sp : string;
 begin
-  if LongFormat then sp := ' ' else sp := '';
+  MillisecondsToString(aMilliseconds.ToExtended,pfTruncate,LongFormat);
+end;
 
-  if aMilliseconds < MSecsPerSec then //milliseconds
-  begin
-    Result := Format('%d%s%s',[aMilliseconds,sp,GetUnitTime(utMillisecond,LongFormat)]);
-  end
-  else if (aMilliseconds / MSecsPerSec) < SecsPerMin then //seconds
-  begin
-    Result := Format('%d%s%s',[(aMilliseconds div MSecsPerSec),sp,GetUnitTime(utSecond,LongFormat)]);
-  end
-  else if ((aMilliseconds / MSecsPerSec) < SecsPerHour) and ((aMilliseconds mod (SecsPerMin * MSecsPerSec)) = 0) then //minutes
-  begin
-    Result := Format('%d%s%s',[(aMilliseconds div (SecsPerMin * MSecsPerSec)),sp,GetUnitTime(utMinute,LongFormat)]);
-  end
-  else if (aMilliseconds / MSecsPerSec) < SecsPerDay then //hours
-  begin
-    dt := aMilliseconds / MSecsPerSec / SecsPerDay;
-    if LongFormat then
-    begin
-      if (aMilliseconds / MSecsPerSec) > SecsPerHour then Result := FormatDateTime(GetFmtTime(tfHoursAndMinutes,LongFormat),Frac(dt))
-        else Result := FormatDateTime(GetFmtTime(tfMinutesAndSeconds,LongFormat),Frac(dt))
-    end
-    else
-    begin
-      Result := FormatDateTime(GetFmtTime(tfHoursAndMinutes,LongFormat),Frac(dt));
-    end;
-  end
-  else //days
-  begin
-    dt := aMilliseconds / MSecsPerSec / SecsPerDay;
-    Result := Format('%d%s%s, %s', [trunc(dt),sp,GetUnitTime(utDay,LongFormat),FormatDateTime(GetFmtTime(tfHoursAndMinutes,LongFormat),Frac(dt))]);
+class function TChronometer.Precission(aValue : Extended; FormatPrecission : TPrecissionFormat) : Extended;
+begin
+  case FormatPrecission of
+    pfRound : Result := Round(aValue).ToExtended;
+    pfTruncate : Result := Int(aValue);
+    else Result := aValue;
   end;
 end;
 
-class function TChronometer.MillisecondsToString(aMillisecondsWithPrecission : Extended; LongFormat : Boolean = False) : string;
+class function TChronometer.MillisecondsToString(aMilliseconds : Extended; FormatPrecission : TPrecissionFormat = pfFloat; LongFormat : Boolean = False) : string;
 var
   dt : TDateTime;
-  sp : string;
+  mc : Extended;
 begin
-  if LongFormat then sp := '' else sp := ' ';
-  if aMillisecondsWithPrecission < MSecsPerSec then //milliseconds
-  begin
-    Result := Format('%f%s%s',[aMillisecondsWithPrecission,sp,GetUnitTime(utMillisecond,LongFormat)]);
-  end
-  else if (aMillisecondsWithPrecission / MSecsPerSec) < 60 then //seconds
-  begin
-    Result := Format('%f%s%s',[(aMillisecondsWithPrecission / MSecsPerSec),sp,GetUnitTime(utSecond,LongFormat)]);
-  end
-  else if (aMillisecondsWithPrecission / MSecsPerSec) < SecsPerHour then //minutes
+  if aMilliseconds < 1.0 then
   begin
-    Result := Format('%f%s%s',[(aMillisecondsWithPrecission / (SecsPerMin * MSecsPerSec)),sp,GetUnitTime(utMinute,LongFormat)]);
+    mc := frac(aMilliseconds) * 1000;
+    if Int(mc) = 0 then Result := Format('%d%s',[Trunc(frac(mc) * 1000),GetUnitTime(utNanosecond,LongFormat)]) //nanoseconds
+      else Result := Format('%d%s',[Trunc(mc),GetUnitTime(utMicrosecond,LongFormat)]); //microseconds
   end
-  else if (aMillisecondsWithPrecission / MSecsPerSec) < SecsPerDay then //hours
+  else
   begin
-    dt := aMillisecondsWithPrecission / MSecsPerSec / SecsPerDay;
-    if LongFormat then
+    if aMilliseconds < MSecsPerSec then //milliseconds
     begin
-      if (aMillisecondsWithPrecission / MSecsPerSec) > SecsPerHour then Result := FormatDateTime(GetFmtTime(tfHoursAndMinutes,LongFormat),Frac(dt))
-        else Result := FormatDateTime(GetFmtTime(tfMinutesAndSeconds,LongFormat),Frac(dt));
+      aMilliseconds := Precission(aMilliseconds,FormatPrecission);
+      if (FormatPrecission = pfFloat) or (frac(aMilliseconds) > 0) then Result := Format('%f%s',[aMilliseconds,GetUnitTime(utMillisecond,LongFormat)])
+        else Result := Format('%d%s',[Trunc(aMilliseconds),GetUnitTime(utMillisecond,LongFormat)])
     end
-    else
+    else if (aMilliseconds / MSecsPerSec) < SecsPerMin then //seconds
+    begin
+      aMilliseconds := Precission((aMilliseconds / MSecsPerSec),FormatPrecission);
+      if (FormatPrecission = pfFloat) or (frac(aMilliseconds) > 0) then Result := Format('%f%s',[aMilliseconds,GetUnitTime(utSecond,LongFormat)])
+        else Result := Format('%d%s',[Trunc(aMilliseconds),GetUnitTime(utSecond,LongFormat)]);
+    end
+    else if ((aMilliseconds / MSecsPerSec) < SecsPerHour) and ((Round(aMilliseconds) mod (SecsPerMin * MSecsPerSec)) = 0) then //minutes
+    begin
+      aMilliseconds := Precission((aMilliseconds / (SecsPerMin * MSecsPerSec)),FormatPrecission);
+      if (FormatPrecission = pfFloat) or (frac(aMilliseconds) > 0) then Result := Format('%f%s',[aMilliseconds,GetUnitTime(utMinute,LongFormat)])
+        else Result := Format('%d%s',[Trunc(aMilliseconds),GetUnitTime(utMinute,LongFormat)])
+    end
+    else if (aMilliseconds / MSecsPerSec) < SecsPerDay then //hours
+    begin
+      dt := aMilliseconds / MSecsPerSec / SecsPerDay;
+      if LongFormat then
+      begin
+        if (aMilliseconds / MSecsPerSec) > SecsPerHour then Result := FormatDateTime(GetFmtTime(tfHoursAndMinutes,LongFormat),Frac(dt))
+          else Result := FormatDateTime(GetFmtTime(tfMinutesAndSeconds,LongFormat),Frac(dt));
+      end
+      else
+      begin
+        Result := FormatDateTime(GetFmtTime(tfHoursAndMinutes,LongFormat),Frac(dt));
+      end;
+    end
+    else //días
     begin
-      Result := FormatDateTime(GetFmtTime(tfHoursAndMinutes,LongFormat),Frac(dt));
+      dt := aMilliseconds / MSecsPerSec / SecsPerDay;
+      Result := Format('%d%s, %s', [trunc(dt),GetUnitTime(utDay,LongFormat),FormatDateTime(GetFmtTime(tfHoursAndMinutes,LongFormat),Frac(dt))]);
     end;
-  end
-  else //días
-  begin
-    dt := aMillisecondsWithPrecission / MSecsPerSec / SecsPerDay;
-    Result := Format('%d%s%s, %s', [trunc(dt),sp,GetUnitTime(utDay,LongFormat),FormatDateTime(GetFmtTime(tfHoursAndMinutes,LongFormat),Frac(dt))]);
   end;
 end;