2013-03-22 180 views

回答

14

这是我用来从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

+4

在具有夏令时区域的地区将历史数据转换为本地数据需要特殊处理 – mjn 2013-03-22 10:14:17

+0

@mjn这取决于需求。 – 2013-03-22 10:18:24

+0

拥有一个名为UTCDateTime的参数和一个名为UTCDateTime的函数,它们都具有相同的类型,这会使我受到伤害。我认为你的预期用法是使用其中一种或另一种,但它呈现的方式使它看起来像LocalDateTimeFromUTCDateTime()想要调用UTCDateTime函数,但实际上不会,因为它使用UTCDateTime参数。有点混乱。 – 2013-03-22 13:37:34

1

如果您的客户端使用本地Delphi应用程序,这可以通过系统日期函数来完成。

但是,如果你在一个客户机/服务器环境(例如Delphi应用程序是一个Web服务器,客户端只接收HTML页面),你需要转换到用户的本地时间不同。服务器需要知道用户的时区,并进行适当的转换。

而且夏令时如果应用程序需要转换的历史数据可引起头痛 - 你需要知道,如果有在用户的区域影响是DST。

在这些使用情况下,Time Zone Database for Delphi会很有帮助。

TZDB提供了一个简单的数据库和专门的时区类,允许 通过访问时区数据库 项目支持的所有时区。

我不知道有SystemTimeToTzSpecificLocalTime,但只是读取Jon Skeet prefers TZDB时区处理。

9

可以使用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; 
+0

您是否知道SystemTimeToTzSpecificLocalTime是否支持“历史”夏令时信息,如tzdb? – mjn 2013-03-22 10:24:35

+0

在以下情况下,SystemTimeToTzSpecificLocalTime函数可能会错误地计算本地时间: 时区对新旧年份使用不同的UTC偏移量。 要转换的UTC时间和计算的本地时间在不同的年份。 http://msdn.microsoft.com/de-de/library/windows/desktop/ms724949(v=vs.85).aspx – bummi 2013-03-22 10:31:03

+1

上面的代码中有一个小错误。在UnivDateTime2LocalDateTime中,行DateTimeToSystemTime(d,LocalTime);应该读取DateTimeToSystemTime(d,UniversalTime); – 2013-11-06 12:34:38

相关问题