使用GetTickCount递增时间是否安全?

时间:2019-09-12 18:50:22

标签: delphi

我有一个在系统启动时创建的线程。它的工作是按需签名PDF文件。要签名,我需要获取服务器日期/时间。为了避免每次都访问服务器,在创建线程时,我获取了服务器时间和当前滴答计数(GetTickCount),并且在需要当前日期时,我使用以下值进行计算:

CurrentDate := (FServerDate+ (GetTickCount - FInitialTick) / MSecsPerDay);

那是安全的事吗?该代码有效,但是使用这种方法是否有缺点?

1 个答案:

答案 0 :(得分:2)

GetTickCount具有32位分辨率,因此不建议使用它,而应使用GetTickCount64和相关的FInitialTick: Int64变量。如果您的操作系统会话持续40天以上,则可能会看到一些舍入错误。

以下是与XP兼容的版本(如果需要维护):

var
  GetTickXP: Int64Rec;

function GetTickCount64ForXP: Int64; stdcall;
var t32: cardinal;
    t64: Int64Rec absolute result;
begin // warning: GetSystemTimeAsFileTime() is fast, but not monotonic!
  t32 := Windows.GetTickCount;
  t64 := GetTickXP; // (almost) atomic read
  if t32<t64.Lo then
    inc(t64.Hi); // wrap-up overflow after 49 days
  t64.Lo := t32;
  GetTickXP := t64; // (almost) atomic write
end; // warning: FPC's GetTickCount64 doesn't handle 49 days wrap :(

在您的用例中,使用这样的公式是安全的,并且避免每次要求服务器返回时间戳。如果不希望在一段时间后重新启动客户端,则可以每小时或每天询问服务器时间戳,以确保双方同步。

多年来,我们成功使用a similar trick in our mORMot ORM。它只是内置在RestFul ORM中,其字段会自动填充创建或修改时间(TCreateTimeTModTime字段)。

最后一个提示:确保在系统中的任何地方都使用UTC日期/时间。 :)