Dan*_*all 5 unix delphi time timestamp date
我需要的功能UTC变种DateTimeToUnix和UnixToDateTime,所以中国客户能够与德国的服务器进行交互.双方应该能够交换Unix时间戳(UTC,没有DST)并能够通过这种方式进行通信.
在HeidiSQL的一个bug报告中,用户讨论了这个DateTimeToUnix并且UnixToDateTime不关心时区,我在那里找到了以下代码:
function DateTimeToUTC(dt: TDateTime): Int64;
var
tzi: TTimeZoneInformation;
begin
Result := DateTimeToUnix(dt);
GetTimeZoneInformation(tzi);
Result := Result + tzi.Bias * 60;
end;
Run Code Online (Sandbox Code Playgroud)
MSDN 解释 twi.Bias如下:
UTC时间和当地时间之间的所有翻译均基于以下公式:
UTC =当地时间+偏见
偏差是UTC时间和当地时间之间的差异,以分钟为单位.
这听起来合乎逻辑,但由于我不确定上面的代码是否正确,我制作了以下程序来检查它:
// A date in summer time (DST)
Memo1.Lines.add('1401494400'); // 31 May 2014 00:00:00 GMT according to http://www.epochconverter.com/
Memo1.Lines.add(inttostr(DateTimeToUnixUTC(StrToDate('31.05.2014'))));
// A date in winter time
Memo1.Lines.add('567302400'); // 24 Dec 1987 00:00:00 GMT according to http://www.epochconverter.com/
Memo1.Lines.add(inttostr(DateTimeToUnixUTC(StrToDate('24.12.1987'))));
Run Code Online (Sandbox Code Playgroud)
目前德国(GMT + 1 + DST)的产量为:
1401494400
1401490800
567302400
567298800
Run Code Online (Sandbox Code Playgroud)
我预计输出是:
1401494400
1401494400
567302400
567302400
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
PS:对于这个项目,我受到Delphi 6的约束.
你已经找到了DateTimeToUnix和UnixToDateTime.因此,部分转换得到了解决.
您现在需要做的就是在本地和UTC时间之间进行转换.你可以使用DateUtils.TTimeZone类来做到这一点.特别是DateUtils.TTimeZone.ToUniversalTime和DateUtils.TTimeZone.ToLocalTime.
这四个功能为您提供所需的一切.
我想我已经为我的问题找到了一些解决方案。所有这三种解决方案都提供了相同的输出,但是我将尝试找出哪一种是最佳的,并在具有不同语言环境的多台计算机上对其进行测试。
解决方案#1使用TzSpecificLocalTimeToSystemTime且SystemTimeToTzSpecificLocalTime工作正常,但需要Windows XP及更高版本:
(来源:https : //stackoverflow.com/a/15567777/3544341,修改)
// Statically binds Windows API functions instead of calling them dynamically.
// Requires Windows XP for the compiled application to run.
{.$DEFINE USE_NEW_WINDOWS_API}
{$IFDEF USE_NEW_WINDOWS_API}
function SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation: PTimeZoneInformation; var lpUniversalTime,lpLocalTime: TSystemTime): BOOL; stdcall; external kernel32 name 'SystemTimeToTzSpecificLocalTime';
{$ELSE}
function SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation: PTimeZoneInformation; var lpUniversalTime,lpLocalTime: TSystemTime): BOOL; stdcall;
var
h: HModule;
f: function(lpTimeZoneInformation: PTimeZoneInformation; var lpUniversalTime,lpLocalTime: TSystemTime): BOOL; stdcall;
begin
h := LoadLibrary(kernel32);
if h = 0 then RaiseLastOSError;
@f := GetProcAddress(h, 'SystemTimeToTzSpecificLocalTime');
if @f = nil then RaiseLastOSError;
result := f(lpTimeZoneInformation, lpUniversalTime, lpLocalTime);
end;
{$ENDIF}
{$IFDEF USE_NEW_WINDOWS_API}
function TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation: PTimeZoneInformation; var lpLocalTime, lpUniversalTime: TSystemTime): BOOL; stdcall; external kernel32 name 'TzSpecificLocalTimeToSystemTime';
{$ELSE}
function TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation: PTimeZoneInformation; var lpLocalTime, lpUniversalTime: TSystemTime): BOOL; stdcall;
var
h: HModule;
f: function(lpTimeZoneInformation: PTimeZoneInformation; var lpLocalTime, lpUniversalTime: TSystemTime): BOOL; stdcall;
begin
h := LoadLibrary(kernel32);
if h = 0 then RaiseLastOSError;
@f := GetProcAddress(h, 'TzSpecificLocalTimeToSystemTime');
if @f = nil then RaiseLastOSError;
result := f(lpTimeZoneInformation, lpLocalTime, lpUniversalTime);
end;
{$ENDIF}
function UTCToLocalDateTime_WinXP(d: TDateTime): TDateTime;
var
TZI: TTimeZoneInformation;
LocalTime, UniversalTime: TSystemTime;
begin
GetTimeZoneInformation(tzi);
DateTimeToSystemTime(d,UniversalTime);
SystemTimeToTzSpecificLocalTime(@tzi,UniversalTime,LocalTime);
Result := SystemTimeToDateTime(LocalTime);
end;
function LocalDateTimeToUTC_WinXP(d: TDateTime): TDateTime;
var
TZI: TTimeZoneInformation;
LocalTime, UniversalTime: TSystemTime;
begin
GetTimeZoneInformation(tzi);
DateTimeToSystemTime(d,LocalTime);
TzSpecificLocalTimeToSystemTime(@tzi,LocalTime,UniversalTime);
Result := SystemTimeToDateTime(UniversalTime);
end;
Run Code Online (Sandbox Code Playgroud)
解决方案2作为较旧操作系统的解决方法也可以正常工作:
(来源:http : //www.delphipraxis.net/299286-post4.html)
uses DateUtils;
function GetDateTimeForBiasSystemTime(GivenDateTime: TSystemTime; GivenYear: integer): TDateTime;
var
Year, Month, Day: word;
Hour, Minute, Second, MilliSecond: word;
begin
GivenDateTime.wYear := GivenYear;
while not TryEncodeDayOfWeekInMonth(GivenDateTime.wYear, GivenDateTime.wMonth, GivenDateTime.wDay, GivenDateTime.wDayOfWeek, Result) do
Dec(GivenDateTime.wDay);
DecodeDateTime(Result, Year, Month, Day, Hour, Minute, Second, MilliSecond);
Result := EncodeDateTime(Year, Month, Day, GivenDateTime.wHour, GivenDateTime.wMinute, GivenDateTime.wSecond, GivenDateTime.wMilliseconds);
end;
function GetBiasForDate(GivenDateTime: TDateTime): integer;
var
tzi: TIME_ZONE_INFORMATION;
begin
GetTimeZoneInformation(tzi);
if (GivenDateTime < GetDateTimeForBiasSystemTime(tzi.StandardDate, YearOf(GivenDateTime))) and
(GivenDateTime >= GetDateTimeForBiasSystemTime(tzi.DaylightDate, YearOf(GivenDateTime))) then
Result := (tzi.Bias + tzi.DaylightBias) * -1
else
Result := (tzi.Bias + tzi.StandardBias) * -1;
end;
function UTCToLocalDateTime_OldWin(aUTC: TDateTime): TDateTime;
begin
Result := IncMinute(aUTC, GetBiasForDate(aUTC));
end;
function LocalDateTimeToUTC_OldWin(aLocal: TDateTime): TDateTime;
begin
Result := IncMinute(aLocal, GetBiasForDate(aLocal) * -1);
end;
Run Code Online (Sandbox Code Playgroud)
TTimeZone为较新版本的Delphi的用户使用的解决方案#3的结果与上述代码相同:
(David Heffernan提出的解决方案,在我当前的项目中是不可能的,因为我必须绑定到Delphi 6)
uses DateUtils;
{$IF Declared(TTimeZone)}
function UTCToLocalDateTime_XE(aUTC: TDateTime): TDateTime;
begin
result := TTimeZone.Local.ToLocalTime(aUTC);
end;
function LocalDateTimeToUTC_XE(aLocal: TDateTime): TDateTime;
begin
result := TTimeZone.Local.ToUniversalTime(aLocal);
end;
{$IFEND}
Run Code Online (Sandbox Code Playgroud)
现在,我们可以将所有3个解决方案放在一起!:-)
function UTCToLocalDateTime(aUTC: TDateTime): TDateTime;
begin
{$IF Declared(UTCToLocalDateTime_XE)}
result := UTCToLocalDateTime_XE(aUTC);
{$ELSE}
{$IFDEF USE_NEW_WINDOWS_API}
result := UTCToLocalDateTime_WinXP(aUTC);
{$ELSE}
try
result := UTCToLocalDateTime_WinXP(aUTC);
except
on E: EOSError do
begin
// Workaround for Windows versions older than Windows XP
result := UTCToLocalDateTime_OldWin(aUTC);
end
else raise;
end;
{$ENDIF}
{$IFEND}
end;
function LocalDateTimeToUTC(aLocal: TDateTime): TDateTime;
begin
{$IF Declared(LocalDateTimeToUTC_XE)}
result := LocalDateTimeToUTC_XE(aLocal);
{$ELSE}
{$IFDEF USE_NEW_WINDOWS_API}
result := LocalDateTimeToUTC_WinXP(aLocal);
{$ELSE}
try
result := LocalDateTimeToUTC_WinXP(aLocal);
except
on E: EOSError do
begin
// Workaround for Windows versions older than Windows XP
result := LocalDateTimeToUTC_OldWin(aLocal);
end
else raise;
end;
{$ENDIF}
{$IFEND}
end;
Run Code Online (Sandbox Code Playgroud)
获取当前UTC Unix时间戳的一种简单方法是
function NowUTC: TDateTime;
var
st: TSystemTime;
begin
GetSystemTime(st);
result := EncodeDateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
end;
function CurrentUnixUTCTimestamp: int64;
begin
result := DateTimeToUnix(NowUTC);
end;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5011 次 |
| 最近记录: |