时间同步

(从ntp服务器,获得一个格林威治的时间)然后转化成本地时间,

使用该类,就可以不管本地电脑时间,永远得到真正的时间。InternetDateTime 可以不停的读取,效率很高的(只到服务器取一次)。

const
  ATimeSvr: array[0..10] of record
    Host: String;
    Addr: String;
  end = (
    (Host: 'utcnist.colorado.edu'; Addr: '128.138.140.44';),
    (Host: 'time-a.timefreq.bldrdoc.gov'; Addr: '132.163.4.101';),
    (Host: 'time-b.timefreq.bldrdoc.gov'; Addr: '132.163.4.102';),
    (Host: 'time-c.timefreq.bldrdoc.gov'; Addr: '132.163.4.103';),
    (Host: 'nist1.datum.com'; Addr: '209.0.72.7';),
    (Host: 'time.nist.gov'; Addr: '192.43.244.18';),
    (Host: 'time-a.nist.gov'; Addr: '129.6.15.28';),
    (Host: 'time-b.nist.gov'; Addr: '129.6.15.29';),
    (Host: 'time-nw.nist.gov'; Addr: '131.107.1.10';),
    (Host: 'time.windows.com'; Addr: '207.46.130.100';),
    (Host: 'nist1.nyc.certifiedtime.com'; Addr: '208.184.49.129';)
  );

unit InternetDateTime;

interface

uses
  Windows,  Classes,SysUtils,IdDayTime;
type
  TOnRecvDateTime = procedure (Sender : Tobject ; DateTime : TdateTime ;url : String) of object ;
  TOnGetDateTimeError = procedure  (sender : Tobject ; url : String) of object ;

  TimeSync = class(TThread)
  private
    SysTime: TSystemTime;
    FURLIndex : integer ;
    FOnDataRecv: TThreadMethod ;
    FonDateError : TThreadMethod ;
    FOnRecvDateTime: TOnRecvDateTime;
    FOnGetDateTimeError: TOnGetDateTimeError;
    procedure doFOnDataRecv ;
    procedure DoFOnDateError ;
    procedure Execute; override;
  public
    constructor Create(CreateSuspended: Boolean);
    destructor Destroy; override;
    property OnRecvDateTime: TOnRecvDateTime  read FOnRecvDateTime write FOnRecvDateTime;
    property OnGetDateTimeError: TOnGetDateTimeError  read FOnGetDateTimeError write FOnGetDateTimeError;
    procedure Stop;
  end;

  TInternetDateTime = class(TComponent)
  private
    Fts : TimeSync ;
    FRecvTime : TdateTime ;
    FrecvTick : Cardinal ;
    function GetdateTime(): TdateTime ;
  protected
    procedure OnRecvDateTime(sender : Tobject ; newTime : TDateTime; url : String); virtual;
    procedure OnGetDateTimeError(sender : Tobject ; url : String) ; virtual;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property InternetDateTime : TdateTime  Read GetDateTime ;  //如果还没有成功获取到,则返回系统时间
  end;

implementation

{$I TimeSvrs.inc}
{ TimeSync }
constructor TimeSync.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  FOnDataRecv := doFOnDataRecv ;

end;

destructor TimeSync.Destroy;
begin
  inherited;
end;

procedure TimeSync.doFOnDataRecv();
begin
  if Assigned(FOnRecvDateTime) then
    FOnRecvDateTime(self,SystemTimeToDateTime(SysTime),ATimeSvr[FURLIndex].Host );
end;

procedure TimeSync.DoFOnDateError;
begin
  if Assigned(FOnGetDateTimeError) then
    FOnGetDateTimeError(self,ATimeSvr[FURLIndex].Host );
end;

procedure TimeSync.Execute;
var
  TempIdDayTime : TIdDayTime;
  i ,hBias,mBias :integer ;
  TimeStr : String ;
  tzInfo: Time_Zone_Information;
begin
  inherited;
  GetTimeZoneInformation(tzInfo);   //获取当地时区和格林威治的时间差
  hBias:=tzInfo.Bias div 60;
  mBias:=tzInfo.Bias mod 60;
  TempIdDayTime := TIdDayTime.Create(nil);
  try
    for i := low(ATimeSvr) to high(ATimeSvr) do
    begin
      try
        if Terminated  then exit ;
        TempIdDayTime.Host := ATimeSvr[i].Host;
        TimeStr:=Trim(TempIdDayTime.DayTimeStr);
        if Terminated  then exit ;
        SysTime.wYear:=StrToInt(Copy(TimeStr,7,2));
        SysTime.wMonth:=StrToInt(Copy(TimeStr,10,2));
        SysTime.wDay:=StrToInt(Copy(TimeStr,13,2));
        SysTime.wHour:=StrToInt(Copy(TimeStr,16,2));
        SysTime.wMinute:=StrToInt(Copy(TimeStr,19,2));
        SysTime.wSecond:=StrToInt(Copy(TimeStr,22,2));
        SysTime.wMilliseconds:=StrToInt(Copy(TimeStr,32,3));
        SysTime.wYear:=SysTime.wYear+2000;   //对获取的时间进行修正
        SysTime.wHour:=SysTime.wHour-hBias;
        SysTime.wMinute:=SysTime.wMinute-mBias;
        if Assigned( FOnDataRecv) then
        begin
          FURLIndex := i ;
          Synchronize(FOnDataRecv);
        end;
        break ;
      except
        if Assigned( FonDateError) then
        begin
          FURLIndex := i ;
          Synchronize(FonDateError);
        end;
      end;
    end;
  finally
    TempIdDayTime.Free ;
  end;

end;


procedure TimeSync.Stop;
begin
  WaitFor ;
end;

{ TInternetDateTime }

constructor TInternetDateTime.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FrecvTick := GetTickCount ;
  FRecvTime := Now ;

  Fts := TimeSync.Create(true) ;
  Fts.OnRecvDateTime := OnRecvDateTime ;
  Fts.OnGetDateTimeError := OnGetDateTimeError ;
  Fts.Start ;
end;

destructor TInternetDateTime.Destroy;
begin
  Fts.Terminate ;
  fts.Stop ;
  fts.Free ;
  inherited;
end;

function TInternetDateTime.GetdateTime: TdateTime;
begin
  Result := FRecvTime + (GetTickCount -  FrecvTick) / 1000 /60 /60 /24 ;
end;

procedure TInternetDateTime.OnGetDateTimeError(sender: Tobject; url: String);
begin

end;

procedure TInternetDateTime.OnRecvDateTime(sender: Tobject; newTime: TDateTime; url : String);
begin
  FrecvTick := GetTickCount ;
  FRecvTime := newTime ;
end;

end.

使用方法:

procedure TMainFrm.Button2Click(Sender: TObject);
var
  s : string ;
begin
  s := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',Itt.InternetDateTime) ;
  Memo1.Lines.Add(format('本机时间%s,真正时间%s',[FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',now),s])) ;
end;

procedure TMainFrm.FormCreate(Sender: TObject);
begin
  itt := TInternetDateTime.Create(self);
end;

procedure TMainFrm.FormDestroy(Sender: TObject);
begin
  if  Assigned (Itt) then
    FreeAndNil( itt) ;
end;

posted on 2011-10-20 16:04  fishzhm  阅读(634)  评论(5)    收藏  举报