Speaking about the most glamorous features of Delphi 2010 we overlooked some other features which, perhaps, seems smaller but sometimes are very useful in the day-by-day work. This is the new
Diagnostics.pas unit which,… at least for the time being, has only one record, TStopwatch.
It’s public part is as following:
TStopwatch = record //snipped public class function Create: TStopwatch; static; class function GetTimeStamp: Int64; static; procedure Reset; procedure Start; class function StartNew: TStopwatch; static; procedure Stop; property Elapsed: TTimeSpan read GetElapsed; property ElapsedMilliseconds: Int64 read GetElapsedMilliseconds; property ElapsedTicks: Int64 read GetElapsedTicks; property IsRunning: Boolean read FRunning; public class var Frequency: Int64; public class var IsHighResolution: Boolean; end;
The most interesting thing above is the new TTimeSpan data type which is declared in the new
TimeSpan.pas which of course has a bunch of interesting things inside (comments mine):
TTimeSpan = record //snipped public const //classical time constants TicksPerMillisecond = 10000; TicksPerSecond = 1000 * Int64(TicksPerMillisecond); TicksPerMinute = 60 * Int64(TicksPerSecond); TicksPerHour = 60 * Int64(TicksPerMinute); TicksPerDay = 24 * TIcksPerHour; public //different 'record constructors' for data initialization constructor Create(ATicks: Int64); overload; constructor Create(Hours, Minutes, Seconds: Integer); overload; constructor Create(Days, Hours, Minutes, Seconds: Integer); overload; constructor Create(Days, Hours, Minutes, Seconds, Milliseconds: Integer); overload; //misc operations via methods function Add(const TS: TTimeSpan): TTimeSpan; overload; function Duration: TTimeSpan; function Negate: TTimeSpan; function Subtract(const TS: TTimeSpan): TTimeSpan; overload; //conversions from temporal representations in different time units class function FromDays(Value: Double): TTimeSpan; static; class function FromHours(Value: Double): TTimeSpan; static; class function FromMinutes(Value: Double): TTimeSpan; static; class function FromSeconds(Value: Double): TTimeSpan; static; class function FromMilliseconds(Value: Double): TTimeSpan; static; class function FromTicks(Value: Int64): TTimeSpan; static; //'convert' from string - the Unit hides a TTimeSpanParser record type in it. class function Parse(const S: string): TTimeSpan; static; class function TryParse(const S: string; out Value: TTimeSpan): Boolean; static; //operator overloading class operator Add(const Left, Right: TTimeSpan): TTimeSpan; class operator Subtract(const Left, Right: TTimeSpan): TTimeSpan; class operator Equal(const Left, Right: TTimeSpan): Boolean; class operator NotEqual(const Left, Right: TTimeSpan): Boolean; class operator GreaterThan(const Left, Right: TTimeSpan): Boolean; class operator GreaterThanOrEqual(const Left, Right: TTimeSpan): Boolean; class operator LessThan(const Left, Right: TTimeSpan): Boolean; class operator LessThanOrEqual(const Left, Right: TTimeSpan): Boolean; class operator Negative(const Value: TTimeSpan): TTimeSpan; class operator Positive(const Value: TTimeSpan): TTimeSpan; //wowza!! seamless conversion to string - that's nice... class operator Implicit(const Value: TTimeSpan): string; class operator Explicit(const Value: TTimeSpan): string; //data representation in different formats property Ticks: Int64 read FTicks; property Days: Integer read GetDays; property Hours: Integer read GetHours; property Minutes: Integer read GetMinutes; property Seconds: Integer read GetSeconds; property Milliseconds: Integer read GetMilliseconds; property TotalDays: Double read GetTotalDays; property TotalHours: Double read GetTotalHours; property TotalMinutes: Double read GetTotalMinutes; property TotalSeconds: Double read GetTotalSeconds; property TotalMilliseconds: Double read GetTotalMilliseconds; //different constants exposed via properties class property MinValue: TTimeSpan read FMinValue; class property MaxValue: TTimeSpan read FMaxValue; class property Zero: TTimeSpan read FZero; end;
Perhaps we must stress that this is the Delphi representation for a time interval. It is not a replacement for
TDateTime which represents a single date – a single point in time.
And now the commented example:
procedure TfrmRibbonDemo.Button1Click(Sender: TObject); var rStopwatch: TStopwatch; I: Integer; begin rStopwatch.Reset; //very good to be here ;-), especially if we want to run this procedure many times rStopwatch.Start; //let's profile! for I := 0 to 100 do //something to do - which will last a little RichEdit1.Lines.Add('x'); rStopwatch.Stop; //stop the timer ShowMessage(rStopwatch.Elapsed); //show what we got - we use the implicit conversion to string end;
Well, I think that the main advantage of using
TStopwatch instead of old ways of time measuring besides of having clean and readable code – one who read the code will understand immediately what’s going on – is that it is abstract. No variables to manage and what’s more interesting is that it tries the best timing method available. See for yourself (code snipped from Diagnostics.pas):
class procedure TStopwatch.InitStopwatchType; begin if Frequency = 0 then begin if not QueryPerformanceFrequency(Frequency) then begin IsHighResolution := False; Frequency := TicksPerSecond; TickFrequency := 1.0; end else begin IsHighResolution := True; TickFrequency := 10000000.0 / Frequency; end; end; end;
In other words it tries to use the high resolution timer if available, but if it doesn’t succeed it goes on the common path of
GetTickCount – not shown in the above snippet.
Well, it seems that there are enough enhancements out there regarding to time handling. What do You think?