Clock drift on Windows

后端 未结 13 716
无人共我
无人共我 2020-12-28 18:42

I\'ve developed a Windows service which tracks business events. It uses the Windows clock to timestamp events. However, the underlying clock can drift quite dramatically (e.

13条回答
  •  -上瘾入骨i
    2020-12-28 19:21

    I once wrote a Delphi class to handle time resynchs. It is pasted below. Now that I see the "w32tm" command mentioned by Larry Silverman, I suspect I wasted my time.

    unit TimeHandler;
    
    interface
    
    type
      TTimeHandler = class
      private
        FServerName : widestring;
      public
        constructor Create(servername : widestring);
        function RemoteSystemTime : TDateTime;
        procedure SetLocalSystemTime(settotime : TDateTime);
      end;
    
    implementation
    
    uses
      Windows, SysUtils, Messages;
    
    function NetRemoteTOD(ServerName :PWideChar; var buffer :pointer) : integer; stdcall; external 'netapi32.dll';
    function NetApiBufferFree(buffer : Pointer) : integer; stdcall; external 'netapi32.dll';
    
    type
      //See MSDN documentation on the TIME_OF_DAY_INFO structure.
      PTime_Of_Day_Info = ^TTime_Of_Day_Info;
      TTime_Of_Day_Info = record
        ElapsedDate : integer;
        Milliseconds : integer;
        Hours : integer;
        Minutes : integer;
        Seconds : integer;
        HundredthsOfSeconds : integer;
        TimeZone : LongInt;
        TimeInterval : integer;
        Day : integer;
        Month : integer;
        Year : integer;
        DayOfWeek : integer;
      end;
    
    constructor TTimeHandler.Create(servername: widestring);
    begin
      inherited Create;
      FServerName := servername;
    end;
    
    function TTimeHandler.RemoteSystemTime: TDateTime;
    var
      Buffer : pointer;
      Rek : PTime_Of_Day_Info;
      DateOnly, TimeOnly : TDateTime;
      timezone : integer;
    begin
      //if the call is successful...
      if 0 = NetRemoteTOD(PWideChar(FServerName),Buffer) then begin
        //store the time of day info in our special buffer structure
        Rek := PTime_Of_Day_Info(Buffer);
    
        //windows time is in GMT, so we adjust for our current time zone
        if Rek.TimeZone <> -1 then
          timezone := Rek.TimeZone div 60
        else
          timezone := 0;
    
        //decode the date from integers into TDateTimes
        //assume zero milliseconds
        try
          DateOnly := EncodeDate(Rek.Year,Rek.Month,Rek.Day);
          TimeOnly := EncodeTime(Rek.Hours,Rek.Minutes,Rek.Seconds,0);
        except on e : exception do
          raise Exception.Create(
                                 'Date retrieved from server, but it was invalid!' +
                                 #13#10 +
                                 e.Message
                                );
        end;
    
        //translate the time into a TDateTime
        //apply any time zone adjustment and return the result
        Result := DateOnly + TimeOnly - (timezone / 24);
      end  //if call was successful
      else begin
        raise Exception.Create('Time retrieval failed from "'+FServerName+'"');
      end;
    
      //free the data structure we created
      NetApiBufferFree(Buffer);
    end;
    
    procedure TTimeHandler.SetLocalSystemTime(settotime: TDateTime);
    var
      SystemTime : TSystemTime;
    begin
      DateTimeToSystemTime(settotime,SystemTime);
      SetLocalTime(SystemTime);
      //tell windows that the time changed
      PostMessage(HWND_BROADCAST,WM_TIMECHANGE,0,0);
    end;
    
    end.
    

提交回复
热议问题