Delphi 跨平台的实施时间(以毫秒为单位)

Implement Time in Milliseconds for Cross platform in Delphi

我在 Delphi(在 Windows)中有一段代码,我使用 RAD Studio 实现了跨平台。 这是代码:

uses SysUtils, Windows, DateUtils;

type
  TSystem_Time = record
    wYear: word;
    wMonth: word;
    wDayOfWeek: word;
    wDay: word;
    wHour: word;
    wMinute: word;
    wSecond: word;
    wMilliseconds: word;
  end;

function DatumInSeconds2(y, m, d, h, mi, s: word): longword;
var
  RelDay: longword;
begin
  if y >= 1970 then
    dec(y, 1900)
  else if y < 70 then
    inc(y, 100); // 00..69 -> 100..169
  if (y < 70) or (y > 169) or (m < 1) or (m > 12) or (d < 1) or (d > 31) then
  begin
    DatumInSeconds2 := 0;
    exit;
  end;
  while m > 1 do
  begin
    dec(m);
    d := d + DaysInMonth[m];
    if (m = 2) and ((y mod 4) = 0) then
      inc(d); { gilt auch fuer Jahr 2000 }
  end;
  RelDay := longword(365) * longword(y - 70) + // Tage in den Vorjahren
    longword((y - 69) div 4) + // Schalttage in den Vorjahren
    d - 1;
  DatumInSeconds2 := ((RelDay * longword(24) + h) * longword(60) + mi) *
    longword(60) + s
end;

function GetTimeInMilliSeconds_Windows: Int64; // For windows
var
  stt: TSystemTime;
  secFrom1900: Int64;
  UtcSystemTime: TSystemTime;
  LocalFileTime: TFileTime;
  UTCFileTime: TFileTime;

begin
  Writeln('Enter GetTimeInMilliSeconds_Windows');
  GetTimeInMilliSeconds_Windows := 0;
  { W1035 Return value of function 'GetTimeInMilliSeconds' might be undefined }
  GetSystemTime(stt);
  SystemTimeToFileTime(stt, LocalFileTime);
  // Local System Time -> Local File Time
  if LocalFileTimeToFileTime(LocalFileTime, UTCFileTime) then
    // Local File Time -> UTC File Time
    if FileTimeToSystemTime(UTCFileTime, UtcSystemTime) then
    begin // Local File Time -> UTC System Time
      with UtcSystemTime do
      begin
        secFrom1900 := DatumInSeconds2(wYear, wMonth, wDay, wHour, wMinute,
          wSecond) + 2208988800;
        Writeln('secFrom1900', secFrom1900);
        Writeln('wYear', wYear);
        Writeln('wMonth', wMonth);
        Writeln('wDay', wDay);
        Writeln('wHour', wHour);
        Writeln('wMinute', wMinute);
        Writeln('wSecond', wSecond);
        Writeln('wMilliseconds', wMilliseconds);
        GetTimeInMilliSeconds_Windows := (secFrom1900 * 1000) + wMilliseconds;
      end;
    end
    else
    begin
      // In case the conversion to UTC fails, return the timestamp in local time.
      with stt do
      begin
        secFrom1900 := DatumInSeconds2(wYear, wMonth, wDay, wHour, wMinute,
          wSecond) + 2208988800;
        GetTimeInMilliSeconds_Windows := (secFrom1900 * 1000) + wMilliseconds;
      end;
    end;
end;

function GetTimeInMilliSeconds_Crossplatform: Int64; // crossplatform code
var
  dtNow, newdt: TDateTime;
  st: TSystem_Time;
  secFrom1900: Int64;

begin
  Writeln('Enter GetTimeInMilliSeconds_Crossplatform');
  GetTimeInMilliSeconds_Crossplatform := 0;
  dtNow := Now;
  newdt := TTimeZone.Local.ToUniversalTime(dtNow);
  DecodeDateTime(newdt, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute,
    st.wSecond, st.wMilliseconds);
  with st do
  begin
    secFrom1900 := DatumInSeconds2(wYear, wMonth, wDay, wHour, wMinute, wSecond)
      + 2208988800;
    // secFrom1900:= DateTimeToUnix(newdt) + 2208988800;
    Writeln('secFrom1900', secFrom1900);
    Writeln('wYear', wYear);
    Writeln('wMonth', wMonth);
    Writeln('wDay', wDay);
    Writeln('wHour', wHour);
    Writeln('wMinute', wMinute);
    Writeln('wSecond', wSecond);
    Writeln('wMilliseconds', wMilliseconds);
    GetTimeInMilliSeconds_Crossplatform := (secFrom1900 * 1000) +
      st.wMilliseconds;
  end;
end;

这是输出:

Enter GetTimeInMilliSeconds_Windows
secFrom19003830898396
wYear2021
wMonth5
wDay25
wHour2
wMinute26
wSecond36
wMilliseconds551
Original_GetTimeInMilliSeconds>>3830898396551
sec3830898396
Enter GetTimeInMilliSeconds_Crossplatform
secFrom19003830918196
wYear2021
wMonth5
wDay25
wHour7
wMinute56
wSecond36
wMilliseconds560
Test_GetTimeInMilliSeconds>>3830918196560

所以这里的问题是当我尝试执行它们时,两者在小时和分钟上都不同。谁能建议一些想法如何解决这个问题?或者可能需要另一种方法来实现它? 提前致谢。

首先关于您当前function GetTimeInMilliSeconds_Windows: Int64;中的错误。错误不是我说的固定3小时。这对我来说是 3 小时,因为我住在芬兰,我们的时区是 UTC + 2 小时 + 1 小时 DST。错误与 UTC 时间和本地时间之间的差异相同。

错误发生是因为您调用了两个不同的函数,convert/return 从本地时间到 UTC。下面是函数调用和来自 MSDN 的简要说明。

GetSystemTime(stt); - Retrieves the current system date and time in Coordinated Universal Time (UTC) format

result: 2021, 5, 2, 25, 15, 23, 39, 219, Time: 15.23.39. My actual local time is 18.23.39

SystemTimeToFileTime(stt, LocalFileTime); - Converts a system time to file time format. System time is based on Coordinated Universal Time (UTC).

LocalFileTimeToFileTime(LocalFileTime, UTCFileTime) - Converts a local file time to a file time based on the Coordinated Universal Time (UTC).

FileTimeToSystemTime(UTCFileTime, UtcSystemTime) - Converts a file time to system time format. System time is based on Coordinated Universal Time (UTC).

result: 2021, 5, 2, 25, 12, 23, 39, 219, Time: 12.23.39

这是我对更好(在我看来)解决方案的建议。由于您没有说明您有什么样的用例,您可能必须根据需要应用它。无论如何,结果是自 1900 年初以来的 nr 毫秒。

function GetTimeInMilliSeconds_Crossplatform: Int64;
var
  dtNow: TDateTime;
  epoch: TDatetime;
  st: TSystemTime;
  secsbetween, msecsBetween: int64;
begin
  // define
  epoch := EncodeDateTime(1900, 1, 1, 0, 0, 0, 0);

  // get current local date time
  dtNow := Now;
  // Memo1.Lines.Add('DtToS, loc: '+DateTimeToStr(dtNow));

  // or get current date time as UTC
  dtNow := TTimeZone.Local.ToUniversalTime(Now);
  // Memo1.Lines.Add('DtToS, utc: '+DateTimeToStr(dtNow));

  // Convert to date and time record if required
  DecodeDateTime(dtNow, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);

  // convert to milliseconds from 1900.01.01 00.00.00
  msecsBetween := MilliSecondsBetween(dtNow, epoch);
  // Memo1.Lines.Add(Format('Milliseconds since epoch = %d',[msecsBetween]));
  
  result := msecsBetween;
end;