【问题标题】:How to convert Local time to UTC time in Delphi? and how to convert it back from UTC to local time?Delphi如何将当地时间转换为UTC时间?以及如何将其从 UTC 转换回本地时间?
【发布时间】:2013-03-12 02:58:17
【问题描述】:

我正在使用 Delphi,我正在尝试在我的数据库中使用 UTC 日期时间存储记录,然后当客户在他的本地日期时间读取它时将其恢复回来?知道如何进行这种来回转换吗?

【问题讨论】:

    标签: delphi datetime time delphi-xe2 utc


    【解决方案1】:

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

    但是,如果您处于客户端/服务器环境中(例如 Delphi 应用程序是一个 Web 服务器,并且客户端只接收 HTML 页面),您需要以不同的方式转换为用户的本地时间。服务器需要知道用户的时区,并进行适当的转换。

    如果应用程序需要转换历史数据,夏令时也会引起头疼 - 您需要知道用户所在地区是否有夏令时。

    在这些用例中,Time Zone Database for Delphi 会很有帮助。

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

    我不知道有 SystemTimeToTzSpecificLocalTime 但只是阅读Jon Skeet prefers TZDB 进行时区处理。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        当您使用 XE2 时,您可以使用 System.DateUtils.TTimeZone

        您可以查看此good post,解释方法及其工作原理和示例: http://alex.ciobanu.org/?p=373

        【讨论】:

        • 我认为它不适用于夏令时 30 分钟的国家/地区。
        【解决方案4】:

        您可以使用 kernel32 中的 TzSpecificLocalTimeToSystemTime 和 SystemTimeToTzSpecificLocalTime。

        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?
        • SystemTimeToTzSpecificLocalTime 函数在以下情况下可能会错误地计算本地时间: 时区对旧年和新年使用不同的 UTC 偏移量。要转换的 UTC 时间和计算的本地时间是不同年份的。 msdn.microsoft.com/de-de/library/windows/desktop/…
        • 上面的代码有一个小错误。在 UnivDateTime2LocalDateTime 中,行 DateTimeToSystemTime(d,LocalTime);应该读 DateTimeToSystemTime(d,UniversalTime);
        【解决方案5】:
        function NowUTC: TDateTime;
        Var UTC: TSystemTime;
        begin
          GetSystemTime(UTC);
          Result := SystemTimeToDateTime(UTC);
        end;
        
        function UTCToLocal(UTC: TDateTime): TDateTime;
        begin
          Result := IncMinute(UTC, UTCToLocalTimeOffsetMinutes);
        end;
        
        function UTCToLocalTimeOffsetMinutes: Int16;
        Var UTC: TSystemTime;
            UTC2: TSystemTime;
            t  : TDateTime;
            t2 : TDateTime;
        begin
          GetSystemTime(UTC);
          GetLocalTime(UTC2);
          t  := SystemTimeToDateTime(UTC);
          t2 := SystemTimeToDateTime(UTC2);
          Result := System.DateUtils.MinutesBetween(t,t2);
        end;
        

        【讨论】:

          【解决方案6】:

          如果有人在 2020 年需要答案:

          确保包含

          Uses 
          System.DateUtils;
          

          那么对于 UTC

          function GetUTC(dt: TDateTime): TDateTime;
          begin
            result := TTimeZone.Local.ToUniversalTime(dt);
          end;
          

          对于当地时间

          function GetLocalTime(dt: TDateTime):TDateTime;
          begin
            result := TTimeZone.Local.ToLocalTime(dt);
          end;
          

          【讨论】:

          • DST 为 30 分钟时至少在 XE2 中不起作用。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-08-13
          • 1970-01-01
          • 2018-07-27
          • 2019-03-30
          • 2019-03-04
          • 1970-01-01
          相关资源
          最近更新 更多