I have a piece of code in Delphi (in Windows) which I have implemented for cross platform using RAD Studio. Here is the code:
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;
Here is the output:
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
So the issue here is when I try to execute them both differs in hour and Minute. Can anyone suggest some idea how to resolve this? or may be some another approach is needed to implement it? Thanks in advance .
First about the error in your current function GetTimeInMilliSeconds_Windows: Int64;
. The error is not a fixed 3 hours as I said. It is 3 hours for me as I live in Finland and our time zone is UTC + 2 hours + 1 hour DST. The error is the same as the diff between UTC time and local time.
The error happens because you call two different functions that convert/return from local time to UTC. Below the function calls and a brief description from 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
This is my suggestion for a better (in my mind) solution. As you did not say what kind of use cases you have you may have to apply it as needed. Anyway, the result is nr of milliseconds since beginning of 1900.
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;