频道分类

Delphi 服务器与客户端的时间同步

作者:admin 来源: 日期:2020/2/5 8:55:45 人气: 标签:

 
一、服务器与客户端的时间同步

我们在编程时,需要让客户端与服务器的时间保存一致(同步),这样,对于数据的查询和处理很有必要。比如,防止用户修改当前时间,造成数据逻辑混乱,客户端使用的时间应为服务器时间。

如何处理呢,我们可以使用Delphi Indy组件中的    TIdDayTimeServer和TIdDayTime一对组件。

TIdDayTimeServer用于服务器端,TIdDayTime用于客户端,二级控件只要参数配置好,随时可以校准二者的时间。

只要我们在客户端,通过Timer定时,读取服务器时间,并保持一致。

二、技术准备

1、在服务器端加入TIdDayTimeServer,大多数使用默认参数。

(1)IdDayTimeServer1.DefaultPort

默认端口:1339(通常默认值)

(2)IdDayTimeServer1.Active

True,启动IdDayTimeServer。

False,关闭IdDayTimeServer。

2、在客户端加入TIdDayTimeServer,大多数使用默认参数。

(1)IdDayTime1.Host

服务器IP地址,

(2) IdDayTime1.Port

服务器端口:与服务器端一致。

(3)IdDayTime1.DayTimeStr

返回时间字符串,格式如下:

“星期六, 十月 06, 2018 12:26:27-EST”

这是正常返回的值,通过分析此格式,通过由该字符串,获取相关日期时间的值。

3、SetLocalTime(SysTime) ,设置本地时间(API)

4、系统时间参数,TSystemTime类型,用于设置本地时间,它的数据结构如下:

TSystemTime = record

    wYear: Word;

    wMonth: Word;

    wDayOfWeek: Word;

    wDay: Word;

    wHour: Word;

    wMinute: Word;

    wSecond: Word;

   wMilliseconds: Word;

end;

5、分解DayTimeStr获取,标准时间值函数

CopyDateTime(S)                // 代码参见下文

三、代码如下:

1、服务器

procedure TForm1.Button1Click(Sender: TObject);
begin
  IdDayTimeServer1.DefaultPort := StrToIntDef(Edit1.Text, strtoint(Edit1.Text));
  IdDayTimeServer1.Active := True;
  Memo1.Lines.Add('服务器启动成功');
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
  IdDayTimeServer1.Active := false;
  Memo1.Lines.Add('服务器连接断开!');
end;
2、客户端

function TForm1.CopyDateTime(TimeStr:string):String; // CopyDateTime
var SysTime: TSystemTime;
    tzInfo: Time_Zone_Information;       // 系统参数
    hBias,                               // 小时  偏差
    mBias,                               // 分钟  偏差
    First,Last,Top: Integer;
    S:string;
    i,iYear,iMonth,iDay,iH,iM,iSS:integer;
 
begin
 
// 星期六, 十月 06, 2018 12:26:27-EST        格式
//   1      2    3    4   5 6  7  8          子串序号
  Result:='';
  iYear:=0;
  iMonth:=0;
  iDay:=0;
  iH:=0;
  iM:=0;
  iSS:=0;
  if Length(TimeStr)>30 then
  begin
    First:=0;                                    // 字符首位
    Last:=0;                                     // 字符未位
    Top:=0;                                      // 字符序列号
    for i:=1 to Length(TimeStr) do
    begin
      if (TimeStr[i]=' ') or (TimeStr[i]=',') or (TimeStr[i]=':') or
         (TimeStr[i]='-') or (i=Length(TimeStr)) then  // 断点
      begin
        First:=Last+1;
        Last:=i;
        if i<Length(TimeStr)
          then S:=Copy(TimeStr,First,Last-First)      // 获取一字符
          else S:=Copy(TimeStr,First,Last-First+1);   // 包含最后字符
        S:=Trim(S);                                   // 取消两端空格
        if S<>'' then
        begin
          Top:=Top+1;
//        showmessage(IntToStr(Top)+':  '+S);
          if Top=2 then                                 // 处理月
          begin
            if (S='一月') or (S='Jan') then iMonth:=1;
            if (S='二月') or (S='Feb') then iMonth:=2;
            if (S='三月') or (S='Mar') then iMonth:=3;
            if (S='四月') or (S='Apr') then iMonth:=4;
            if (S='五月') or (S='May') then iMonth:=5;
            if (S='六月') or (S='Jun') then iMonth:=6;
            if (S='七月') or (S='Jul') then iMonth:=7;
            if (S='八月') or (S='Aug') then iMonth:=8;
            if (S='九月') or (S='Sep') then iMonth:=9;
            if (S='十月') or (S='Oct') then iMonth:=10;
            if (S='十一月') or (S='Nev') then iMonth:=11;
            if (S='十二月') or (S='Dec') then iMonth:=12;
          end;
          if Top=3 then                      // 处理日
            iDay:=StrToInt(S);
          if Top=4 then                      // 处理年
            iYear:=StrToInt(S);
          if Top=5 then                      // 处理时
            iH:=StrToInt(S);
          if Top=6 then                      // 处理分
            iM:=StrToInt(S);
          if Top=7 then                      // 处理秒
            iSS:=StrToInt(S);
        end;
      end;
    end;
  end;
// 下面分别向SysTime分解字符串的值
  SysTime.wYear:=iYear;
  SysTime.wMonth:=iMonth;
  SysTime.wDay:=iDay;
  SysTime.wHour:=iH;
  SysTime.wMinute:=iM;
  SysTime.wSecond:=iSS;
  SysTime.wMilliseconds:=0;
// 对获取的SysTime时间值 进行修正
  SysTime.wYear:=SysTime.wYear;                  // 加入日期偏差
  SysTime.wHour:=SysTime.wHour-hBias;            // 加入小时偏差
  SysTime.wMinute:=SysTime.wMinute-mBias;        // 加入小时偏差
  Result:=FormatDateTime('yyyy-mm-dd hh:nn:ss zzz',SystemTimeToDateTime(SysTime));
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
 IdDayTime1.Host := Edit1.Text;                                   // 连接主机
 IdDayTime1.Port := StrToIntDef(Edit2.Text,strtoint(Edit2.Text)); // 端口
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var sDateTime:string;
    DateTime:TDateTime;
    SystemTime: TSystemTime;
begin
  DateSeparator:='-';
  ShortDateFormat:='yyyy-MM-dd';
  LongDateFormat:='yyyy''年'',MM''月'',dd''日''';
  TimeSeparator:=':';
 
  sDateTime:=IdDayTime1.DayTimeStr;
  sDateTime:=CopyDateTime(sDateTime);
  Edit4.Text:=sDateTime;
  DateTime:=StrToDateTime(SDateTime);            // 获得时间(TDateTime格式)
  DateTimeToSystemTime(DateTime,systemtime);     // TDateTime格式转化TSystemTime
  SetLocalTime(SystemTime);                      // 设置系统时间
  GetLocalTime(SystemTime);                      // 读取系统时间
  DateTime:=SystemTimeToDateTime(systemtime);    // TSystemTime格式转化TDateTime
  Edit5.Text:=DateTimetoStr(DateTime);
end;
 
 
procedure TForm1.Timer1Timer(Sender: TObject); // 定时同步 
var sDateTime:string;
    DateTime:TDateTime;
    SystemTime: TSystemTime;
 
begin
  sDateTime:=IdDayTime1.DayTimeStr;
  sDateTime:=CopyDateTime(sDateTime);
  DateTime:=StrToDateTime(SDateTime);          // 获得时间(TDateTime格式)
  DateTimeToSystemTime(DateTime,systemtime);   // TDateTime格式转化TSystemTime格式
  SetLocalTime(SystemTime);                    // 设置系统时间
  StatusBar1.Panels[1].Text:='校正时间:'+sDateTime;
end;
 
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if CheckBox1.Checked then
  begin
    Button1Click(Sender);
    Timer1.Enabled:=True;
  end
  else
    Timer1.Enabled:=False;
end;

————————————————

原文链接:https://blog.csdn.net/lyhoo163/article/details/82950824