web-dev-qa-db-ja.com

Delphi XE2で現地時間をUTC時間に変換する方法は?そしてそれをUTCから現地時間に戻す方法は?

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

12
Dreamer64

これは、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からローカルへの変換です)
  • ローカルファイル時間->システム時間
  • システム時刻->日時

これを逆にする方法は明らかです。


この変換では、夏時間がそのまま/以前の変換時ではなく現在として扱われることに注意してください。 DateUtils.TTimeZone XEで導入されたタイプは、まさにそれを実行しようとします。コードは次のようになります。

LocalDateTime := TTimeZone.Local.ToLocalTime(UniversalDateTime);

他の方向では、ToUniversalTimeを使用します。

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

警告の言葉。 attemptが、変換時に100%正確になるように夏時間を考慮することを期待しないでください。それを達成することは単に不可能です。少なくともタイムマシンなしで。そして、それは将来の時代を考慮しているだけです。過去の時代でさえ複雑です。 Raymond Chenがこの問題についてここで説明しています: 夏時間が直感的でない理由

19
David Heffernan

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;
11
bummi

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

あなたはこれをチェックすることができます 良い投稿 方法とそれがどのように機能するかと例を説明します: http://alex.ciobanu.org/?p=37

10
Whiler

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

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

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

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

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

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

1
mjn