
program TZ_CHECK { J R Stockton ; Written for Delphi 3 : DCC32 -cc } ;

{ I have only been able to test this myself in the UK.

  Scan windows.pas for TTimeZoneInformation,
  see Win32 Help via index for TIME_ZONE_INFORMATION.

  I suspect an error in my Win32 Help, since the transition times
  look as if in Local not GMT; and in the Win98 1st Edn data, as
  UK/EU changes are actually at 0100h GMT.
  }

uses Windows, SysUtils ;


const
T15018 = 15018 ;   // MJD of TDateTime base
T25569 = 25569.0 ; // TDateTime for UNIX base 1970-01-01
Days = ' days.' ;


procedure TryGTC ;
var TSB : cardinal ;
begin ;
  TSB := GetTickCount ;
  Writeln(' GetTickCount : Since Windows boot = ', TSB:20, ' ms,',
    TSB/864E5:7:3, Days) ;
  end {TryGTC} ;


procedure TryQPC ;
var PF, PC : { use int64 if available }
  record Case byte of 0: (L:TLargeInteger); 1: (C:comp) end ;
B : boolean ;
begin ;
  B := QueryPerformanceFrequency(PF.L) ;
  Write(' QueryPerformanceFrequency :') ;
  if B then Write(' ', PF.C:15:0, ' Hz') else write(B) ; Writeln ;
  if B then begin B := QueryPerformanceCounter(PC.L) ;
    Write('   QueryPerformanceCounter =') ;
    if B then Write(' ', PC.C:15:0,
      PC.C/PF.C:13:3, ' s, ', PC.C/PF.C/86400:7:3, Days) else write(B) ;
    Writeln ;
    end ;
  end {TryQPC} ;


procedure TryRDTSC ;

{ RDTSC instruction needs Pentium or better, returns count of CPU clock
  cycles ; only for certain processors.  ** See RDTSC.PAS ** }

function FrdtscL : longint ; assembler ;
asm  dw $310F {Clock to edx:eax}  end {FrdtscL} ;

procedure GetCycleCount(var Lo, Hi : integer) { tested in longcalc.pas } ;
asm  push ebx ; mov ecx,eax ; mov ebx,edx
  DB 0FH ; DB 031H
  mov dword ptr[ecx], eax ; mov dword ptr[ebx], edx
  pop ebx  end {Bob Lee} ;

type LH = record L, H : integer end {no Int64 in my D3} ;

var R : comp ; T0, T1 : longint ;

begin ;
  Write(' RDTSC : Approximate CPU speed = ') ;
  T0 := FrdtscL ; Sleep(1000) ; T1 := FrdtscL ; Dec(T1, T0) ;
  Writeln(T1:11, ' Hz') ;

  with LH(R) do GetCycleCount(L, H) ;

  Writeln('   CPU cycles', R:20:0,
    ',  so about ', R/T1:12:3, ' s, ', R/T1/86400:7:3, Days) ;

  end {TryRDTSC} ;


function ShowTime(const D : TSystemTime) : string ;
const DN : array [0..6] of string [3] =
  ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat') ;
begin with D do begin
  if WMonth=0 then begin Result := ' Unspecified' ; EXIT end ;
  if WYear=0 then Result := Format(' Month %2.2d, %s #%d',
    [wMonth, DN[wDayOfWeek], wDay])
    else Result := Format(' %4.4d-%2.2d-%2.2d, %s ',
    [wYear, wMonth, wDay, DN[wDayOfWeek]]) ;
  Result := Result + Format(' @ %2.2d:%2.2d:%2.2d.%3.3d',
    [wHour, wMinute, wSecond, wMilliseconds])
    end ;
  end {ShowTime} ;


procedure TrySysTim ;
var ST : TSystemTime ;
begin ;
  GetSystemTime(ST) ;
  Writeln(' GetSystemTime : ', ShowTime(ST), ' GMT') ;
  with ST do Writeln('   => UNIX seconds count = ',
    (((Trunc(EncodeDate(wYear, wMonth, wDay))-T25569)*24
      +wHour)*60+wMinute)*60+wSecond:1:0) ;
  end {TrySysTim} ;


function ItIs(const T : TDateTime) : string ;
var Yr, Mo, Dy, H, M, S, C : word ;
begin DecodeDate(T, Yr, Mo, Dy) ; DecodeTime(T, H, M, S, C) ;
  Result := Format(' %d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d ',
    [Yr, Mo, Dy, H, M, S]) end {ItIs} ;


function W2(const Bias : integer ; Season : string) : string ;
var Q : double ;
begin Q := 12.000001 - Bias/60 ;
  W2 := Format(' : %s %2.2d:%2.2d', [Season, Trunc(Q), Round(60*Frac(Q))]) ;
  end {W2} ;


procedure TryGTZI(const TDT : TDateTime) ;
var GTZI : cardinal ; TZI : TTimeZoneInformation ;
TD : TDateTime ; Card : cardinal ; WinterDiff, SummerDiff : integer ;
const TZID : array [0..2] of string [21] = ('',
  'TIME_ZONE_ID_STANDARD', 'TIME_ZONE_ID_DAYLIGHT') ;
begin ;

  GTZI := GetTimeZoneInformation(TZI) ;
  Write(' According to Windows :  GTZI = ', GTZI, '  =>  ') ;

  if GTZI=TIME_ZONE_ID_INVALID then begin
    Writeln('TIME_ZONE_ID_INVALID.') ; EXIT end ;

  with TZI do begin


    {$IFDEF TEST} BIAS:=-330 ; DAYLIGHTBIAS:=0; STANDARDBIAS:=0; {$ENDIF}


    Writeln(TZID[GTZI]) ;
    Writeln('   Bias = ', Bias,
      '  StandardBias = ', StandardBias,
      '  DaylightBias = ', DaylightBias, '   (minutes)') ;

    WinterDiff := Bias + StandardBias ;
    SummerDiff := Bias + DaylightBias ;

    Writeln('   At midday GMT, local time is',
      W2(WinterDiff, 'Winter'), W2(SummerDiff, 'Summer')) ;
    Writeln ;

    if SummerDiff <> WinterDiff then Writeln(
      Format('   %s', [DaylightName]),
        ' after', ShowTime(DaylightDate), ' civil'^M^J,
      Format('   %s', [StandardName]),
        ' after', ShowTime(StandardDate), ' civil'^M^J) ;

    case GTZI of
      0 : {TIME_ZONE_ID_UNKNOWN } TD := TDT + Bias/1440 { ? } ;
      1 : {TIME_ZONE_ID_STANDARD} TD := TDT + WinterDiff/1440 ;
      2 : {TIME_ZONE_ID_DAYLIGHT} TD := TDT + SummerDiff/1440 ;
      else begin Writeln('   *** GTZI = ', GTZI, ' ***') ; EXIT end ;
      end ;

    Writeln('   GMT =', ItIs(TD),
      '   True (GMT) MJD = ', Trunc(TD) + T15018,
      '   JD = ', (TD + T15018 + 2400000.5):1:3) ;

    Write('   UNIX time_t = ') ;
    Card := Round( ( TD - T25569 ) * 86400 ) ;
    Writeln(Card, ' sec, from 1970-01-01 00:00:00 GMT.') ;

    end { w TZI } ;
  end {TryGTZI} ;



procedure TryTDT(const DT : TDateTime) ;
begin ;
  Writeln(' Delphi : Now = ', DT:1:6,
    '   Date = ', Date:1:0, '   Time = ', Time:1:6) ;
  Writeln('   It is', ItIs(DT),
    '   Local MJD (CMJD) = ', (Trunc(DT) + T15018)) ;
  end {TryTDT} ;


var TN : TDateTime ;

BEGIN ;
Writeln('TZ_CHECK (c) www.merlyn.demon.co.uk >= 2003-09-12 See Win32 Help') ;
Writeln(' Test and demonstration of some Win32 Date/Time system routines.') ;
TN := Now ;

Writeln ; TryTDT(TN) ; Writeln ; TrySysTim ; Writeln ; TryGTZI(TN) ;
Writeln ; TryGTC ; Writeln ; TryQPC ; Writeln ; TryRDTSC ;
END.



