18

私は Delphi を使用しており、データベースに UTC 日時を使用してレコードを保存し、クライアントがローカル日時で読み取ったときにそれを復元しようとしていますか? これを逆変換する方法はありますか?

4

6 に答える 6

25

これは、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

このクラスは、(大まかに) .netTimeZoneクラスでモデル化されているようです。

警告の言葉。変換時の夏時間を考慮する試みが 100% 正確であるとは期待しないでください。それを達成することは単に不可能です。少なくともタイムマシンはありません。そして、それは将来の時間を考慮しているだけです。過去の時代でさえ複雑です。Raymond Chen がこの問題について議論しています: Why Daylight Savings Time is nonintuitive .

于 2013-03-22T09:57:17.140 に答える
12

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;
于 2013-03-22T10:14:34.687 に答える
10

XE2を使用しているので、を使用できますSystem.DateUtils.TTimeZone

メソッドとその仕組みおよび例を説明する この良い投稿を確認できます: http ://alex.ciobanu.org/?p = 373

于 2013-03-22T10:11:01.763 に答える
1

クライアントがローカルの Delphi アプリケーションを使用している場合、これはシステム日付関数で実行できます。

ただし、クライアント/サーバー環境(たとえば、Delphi アプリケーションが Web サーバーであり、クライアントが HTML ページのみを受信する場合)にいる場合は、別の方法でユーザーの現地時間に変換する必要があります。サーバーはユーザーのタイムゾーンを認識し、適切に変換する必要があります。

また、アプリケーションが履歴データを変換する必要がある場合、夏時間が頭痛の種になる可能性があります。ユーザーの地域で DST が有効になっているかどうかを知る必要があります。

これらのユース ケースでは、Delphi のタイム ゾーン データベースが役立ちます。

TZDB は、単純なデータベースと、タイム ゾーン データベース プロジェクトでサポートされているすべてのタイム ゾーンにアクセスできる特殊なタイム ゾーン クラスを提供します。

SystemTimeToTzSpecificLocalTime があることは知りませんでしたが、 Jon Skeet がタイム ゾーンの処理にTZDB を好むことを読んだだけです。

于 2013-03-22T09:56:22.860 に答える