如何在Delphi XE2中将本地时间转换为UTC时间?以及如何将其从UTC转换回当地时间?
我正在使用Delphi xe2,我试图在我的数据库中存储使用UTC datetime的记录,然后在客户端在本地日期时间读取它时恢复它。任何想法如何做到这一点后退转换?如何在Delphi XE2中将本地时间转换为UTC时间?以及如何将其从UTC转换回当地时间?
这是我用来从UTC转换到本地的功能。
function LocalDateTimeFromUTCDateTime(const UTCDateTime: TDateTime): TDateTime;
var
LocalSystemTime: TSystemTime;
UTCSystemTime: TSystemTime;
LocalFileTime: TFileTime;
UTCFileTime: TFileTime;
begin
DateTimeToSystemTime(UTCDateTime, UTCSystemTime);
SystemTimeToFileTime(UTCSystemTime, UTCFileTime);
if FileTimeToLocalFileTime(UTCFileTime, LocalFileTime)
and FileTimeToSystemTime(LocalFileTime, LocalSystemTime) then begin
Result := SystemTimeToDateTime(LocalSystemTime);
end else begin
Result := UTCDateTime; // Default to UTC if any conversion function fails.
end;
end;
正如你所看到的功能转换的UTC日期时间如下:
- 日期时间 - >系统时间
- 系统时间 - >文件时间
- 文件时间 - >本地文件时间(这是从UTC到本地的转换)
- 本地文件时间 - >系统时间
- 系统时间 - >日期时间
这应该是显而易见如何扭转这一点。
注意,此转换对待夏令因为它是现在而不是因为它是/是当时被转换。在XE中引入的DateUtils.TTimeZone
类型试图做到这一点。代码变为:
LocalDateTime := TTimeZone.Local.ToLocalTime(UniversalDateTime);
在另一个方向上使用ToUniversalTime
。
该类似乎是(宽松)仿照.NET TimeZone
类。
一句警告。不要指望尝试在转换为100%准确时考虑夏令时。实现这一点根本不可能。至少没有时间机器。这只是考虑未来的时代。过去的时代都很复杂。 Raymond Chen在这里讨论这个问题:Why Daylight Savings Time is nonintuitive。
如果您的客户端使用本地Delphi应用程序,这可以通过系统日期函数来完成。
但是,如果你在一个客户机/服务器环境(例如Delphi应用程序是一个Web服务器,客户端只接收HTML页面),你需要转换到用户的本地时间不同。服务器需要知道用户的时区,并进行适当的转换。
而且夏令时如果应用程序需要转换的历史数据可引起头痛 - 你需要知道,如果有在用户的区域影响是DST。
在这些使用情况下,Time Zone Database for Delphi会很有帮助。
TZDB提供了一个简单的数据库和专门的时区类,允许 通过访问时区数据库 项目支持的所有时区。
我不知道有SystemTimeToTzSpecificLocalTime,但只是读取Jon Skeet prefers TZDB时区处理。
当您使用XE2时,您可以使用System.DateUtils.TTimeZone
。
您可以检查此good post解释的方法和它的工作原理和例子: http://alex.ciobanu.org/?p=373
可以使用TzSpecificLocalTimeToSystemTime和SystemTimeToTzSpecificLocalTime从KERNEL32。
var
Form1: TForm1;
function TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation: PTimeZoneInformation; var lpLocalTime, lpUniversalTime: TSystemTime): BOOL; stdcall;
function SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation: PTimeZoneInformation; var lpUniversalTime,lpLocalTime: TSystemTime): BOOL; stdcall;
implementation
function TzSpecificLocalTimeToSystemTime; external kernel32 name 'TzSpecificLocalTimeToSystemTime';
function SystemTimeToTzSpecificLocalTime; external kernel32 name 'SystemTimeToTzSpecificLocalTime';
{$R *.dfm}
Function DateTime2UnivDateTime(d:TDateTime):TDateTime;
var
TZI:TTimeZoneInformation;
LocalTime, UniversalTime:TSystemTime;
begin
GetTimeZoneInformation(tzi);
DateTimeToSystemTime(d,LocalTime);
TzSpecificLocalTimeToSystemTime(@tzi,LocalTime,UniversalTime);
Result := SystemTimeToDateTime(UniversalTime);
end;
Function UnivDateTime2LocalDateTime(d:TDateTime):TDateTime;
var
TZI:TTimeZoneInformation;
LocalTime, UniversalTime:TSystemTime;
begin
GetTimeZoneInformation(tzi);
DateTimeToSystemTime(d,UniversalTime);
SystemTimeToTzSpecificLocalTime(@tzi,UniversalTime,LocalTime);
Result := SystemTimeToDateTime(LocalTime);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Date,Univdate,DateAgain:TDateTime;
begin
Date := Now;
Univdate := DateTime2UnivDateTime(Date);
DateAgain := UnivDateTime2LocalDateTime(Univdate);
Showmessage(DateTimeToStr(Date) +#13#10 + DateTimeToStr(Univdate)+#13#10 + DateTimeToStr(DateAgain));
end;
您是否知道SystemTimeToTzSpecificLocalTime是否支持“历史”夏令时信息,如tzdb? – mjn 2013-03-22 10:24:35
在以下情况下,SystemTimeToTzSpecificLocalTime函数可能会错误地计算本地时间: 时区对新旧年份使用不同的UTC偏移量。 要转换的UTC时间和计算的本地时间在不同的年份。 http://msdn.microsoft.com/de-de/library/windows/desktop/ms724949(v=vs.85).aspx – bummi 2013-03-22 10:31:03
上面的代码中有一个小错误。在UnivDateTime2LocalDateTime中,行DateTimeToSystemTime(d,LocalTime);应该读取DateTimeToSystemTime(d,UniversalTime); – 2013-11-06 12:34:38
在具有夏令时区域的地区将历史数据转换为本地数据需要特殊处理 – mjn 2013-03-22 10:14:17
@mjn这取决于需求。 – 2013-03-22 10:18:24
拥有一个名为UTCDateTime的参数和一个名为UTCDateTime的函数,它们都具有相同的类型,这会使我受到伤害。我认为你的预期用法是使用其中一种或另一种,但它呈现的方式使它看起来像LocalDateTimeFromUTCDateTime()想要调用UTCDateTime函数,但实际上不会,因为它使用UTCDateTime参数。有点混乱。 – 2013-03-22 13:37:34