私は Delphi を使用しており、データベースに UTC 日時を使用してレコードを保存し、クライアントがローカル日時で読み取ったときにそれを復元しようとしていますか? これを逆変換する方法はありますか?
6 に答える
これは、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 .
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;
XE2を使用しているので、を使用できますSystem.DateUtils.TTimeZone
。
メソッドとその仕組みおよび例を説明する この良い投稿を確認できます: http ://alex.ciobanu.org/?p = 373
クライアントがローカルの Delphi アプリケーションを使用している場合、これはシステム日付関数で実行できます。
ただし、クライアント/サーバー環境(たとえば、Delphi アプリケーションが Web サーバーであり、クライアントが HTML ページのみを受信する場合)にいる場合は、別の方法でユーザーの現地時間に変換する必要があります。サーバーはユーザーのタイムゾーンを認識し、適切に変換する必要があります。
また、アプリケーションが履歴データを変換する必要がある場合、夏時間が頭痛の種になる可能性があります。ユーザーの地域で DST が有効になっているかどうかを知る必要があります。
これらのユース ケースでは、Delphi のタイム ゾーン データベースが役立ちます。
TZDB は、単純なデータベースと、タイム ゾーン データベース プロジェクトでサポートされているすべてのタイム ゾーンにアクセスできる特殊なタイム ゾーン クラスを提供します。
SystemTimeToTzSpecificLocalTime があることは知りませんでしたが、 Jon Skeet がタイム ゾーンの処理にTZDB を好むことを読んだだけです。