Delphi Programming / Object Pascal
[掲載 2019年01月31日] [更新 2019年01月31日] Delphi 一般・その他 |
TDateTime 型とシステム時刻と .NET の DateTime 型の時刻 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32 |
TDateTime 型とシステム時刻と .NET の DateTime 型の時刻 |
以下の 2 つの時刻の値の変換とその逆変換のサンプルです. |
- TDateTime 型とシステムファイル時刻
- TDateTime 型と .NET の DateTime 型の時刻
|
Delphi の TDateTime 日付時刻型は倍精度実数値です.この値が 0 の時は 1899 年 12 月 30 日 0 時0 分 0 秒です.
Windows のシステムファイル時刻 (または単にシステム時刻)
の値は 64 ビットの整数で,1601 年 01 月 01 日 0 時 0 分 0 秒からの経過時間です.時間の単位は 100 ns (ナノ秒) です.
C# 等,.NET の日付時刻の DateTime 型は 64 ビットの整数で,0001 年 01 月 01 日 0 時 0 分 0 秒からの経過時間です.時間の単位は 100 ns (ナノ秒) です.
.NET の DateTime の時刻を Delphi で直接扱うことはありませんが,C# 等で開発したアプリケーションの日付や時刻のデータを扱う時に必要になるかも知れません.
これらの時刻型の値は,以下のリンクの記事の関数類を使用して相互に変換できます. |
01_TDateTime 型とシステムファイル時刻との相互変換 |
Delphi の TDateTime 型の日付時刻の値と,システムファイル時刻との相互変換のサンプルです. |
|
図1
TDateTime 型の値をシステム時刻に変換
- システム時刻を UTC 時刻に換算した結果
- その結果を TDateTime 型の値に変換
|
リスト1
TDateTime 型とシステムファイル時刻との相互変換 |
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
function TDateTimeToSystemFileTime(ADateTime: TDateTime; ToUTC: Boolean=False): Int64;
function SystemFileTimeToTDateTime(AInt64: Int64; ToUTC: Boolean=False): TDateTime;
var
Form1: TForm1;
implementation
uses
DateUtils;
{$R *.dfm}
//=============================================================================
// TDateTime の時刻をシステムファイル時刻の値に変換
// 変換後の値は 1601/1/1 9:0:0 からの経過時間 (単位は 100 ns)
// その逆変換もテスト
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LInt64 : Int64;
LDateTime : TDateTime;
begin
Memo1.Lines.Clear;
LDateTime := StrToDateTime('2019/01/06 17:26:33');
// TDateTime の値をシステム時刻に変換
LInt64 := TDateTimeToSystemFileTime(LDateTime);
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
Memo1.Lines.Add('$' + IntToHex(LInt64, 16));
Memo1.Lines.Add('');
// TDateTime の値をシステム時刻に変換 (UTC に換算して)
LInt64 := TDateTimeToSystemFileTime(LDateTime, True);
Memo1.Lines.Add('$' + IntToHex(LInt64, 16));
// 上で変換した値を TDateTime の値に変換して UTC 時刻になっているかを確認
LDateTime := SystemFileTimeToTDateTime(LInt64);
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
end;
//-----------------------------------------------------------------------------
// Delphi の TDateTime 型の時刻の値をシステムファイルの時刻に変換する関数
// 取得する値は 1601/1/1 0:0:0 からの経過時間(単位は 100 ns)
//
// uses に DateUtils が必要
//-----------------------------------------------------------------------------
function TDateTimeToSystemFileTime(ADateTime: TDateTime; ToUTC: Boolean=False): Int64;
var
LSystemTime : TSystemTime;
LLocalFileTime : TFileTime;
LUTCFileTime : TFileTime;
begin
// TDateTime の時刻をシステム時刻に変換
DateTimeToSystemTime(ADateTime, LSystemTime);
// システム時刻をローカルなファイル時刻に変換
SystemTimeToFileTime(LSystemTime, LLocalFileTime);
if ToUTC then begin
// ローカルのファイル時刻を世界協定時刻 (UTC) ファイル時刻へ換算
LocalFileTimeToFileTime(LLocalFileTime, LUTCFileTime);
Result := Int64(LUTCFileTime);
end else begin
Result := Int64(LLocalFileTime);
end;
end;
//-----------------------------------------------------------------------------
// システムファイルの時刻を Delphi の TDateTime 型の時刻の値に変換する関数
// 引数には 1601/1/1 0:0:0 からの経過時間(単位は 100 ns) を与える
//
// uses に DateUtils が必要
//-----------------------------------------------------------------------------
function SystemFileTimeToTDateTime(AInt64: Int64; ToUTC: Boolean=False): TDateTime;
var
LUTCFileTime : TFileTime;
LSystemTime : TSystemTime;
begin
// UTC に換算した値を取得する場合
if ToUTC then begin
LocalFileTimeToFileTime(TFileTime(AInt64), LUTCFileTime);
FileTimeToSystemTime(LUTCFileTime, LSystemTime);
end else begin
FileTimeToSystemTime(TFileTime(AInt64), LSystemTime);
end;
Result := SystemTimeToDateTime(LSystemTime);
end;
end.
02_TDateTime 型と .NET の DateTime 型の時刻との相互変換 |
.NET の DateTime の値は 64 ビットですが,上位の 2 ビットは UTC (協定世界時) のフラグとして使用されています.残りの 62 ビットが実際の時刻の値です.このフラグが .NET でどのように使われているかの確認はしていません.Delphi のプログラムで時刻型の相互変換用に利用するのが目的なので,このフラグは任意に利用できます.
このフラグは 00 (= 0), 01 (= 1), 10 (= 2) の 3 種類あります.その 3 種類についてテストしています.このフラグは,.NET における DateTime 構造体の Kind メンバに相当します. |
|
図2
[Button1] クリック
- 上から順番に
- TDateTime 型の値をそのまま .NET の DateTime 型の値に変換した結果
- その値をそのまま TDateTime 型の値として取得
- その値の上位 2 ビットを 0 にして TDateTime 型の値に変換した結果
|
|
図3
[Button2] クリック
- 上から順番に
- TDateTime の値を UTC 換算の .NET の DateTime 型の値に変換した結果
- その値をそのまま TDateTime 型の値として取得
- その値の上位 2 ビットを 0 にして TDateTime 型の値に変換した結果
|
|
図4
[Button3] クリック
- 上から順番に
- TDateTime 型の値を UTC の時刻とみなして,ローカルな時刻に変換して .NET の DateTime 型の値に変換した結果
- その値をそのまま TDateTime 型の値として取得
- その値の上位 2 ビットを 0 にして TDateTime 型の値に変換した結果
|
リスト2
TDateTime 型と .NET の DateTime 型の時刻との相互変換 |
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
function DateTimeTodotNETTime(ADateTime: TDateTime; UTCFlag: Byte=0): UInt64;
function dotNETTimeToDateTime(AUInt64: UInt64; ChFlag: Boolean=True): TDateTime;
var
Form1: TForm1;
implementation
uses
DateUtils;
{$R *.dfm}
//=============================================================================
// Delphi の TDateTime の時刻を .NET の DateTime の値に変換
// その逆変換もテスト
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LDateTime : TDateTime;
LInt64 : UInt64;
begin
// 変換元の値
LDateTime := StrToDateTime('2019/01/06 17:25:59');
Memo1.Lines.Clear;
// TDateTime の時刻を .NET の DateTime の値に変換 (UTC の指定なし)
LInt64 := DateTimeTodotNETTime(LDateTime);
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
Memo1.Lines.Add('$' + IntToHex(LInt64, 16));
// 変換後の値を TDateTime 型の値に UTC フラグを考慮して変換
Memo1.Lines.Add('');
LDateTime := dotNETTimeToDateTime(LInt64);
Memo1.Lines.Add('$' +IntToHex(LInt64, 16));
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
// 変換後の値を TDateTime 型の値に UTC フラグを無視して変換
Memo1.Lines.Add('');
LDateTime := dotNETTimeToDateTime(LInt64, False);
Memo1.Lines.Add('$' +IntToHex(LInt64, 16));
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
end;
//=============================================================================
// Delphi の TDateTime の時刻を .NET の DateTime の値に変換
// その逆変換もテスト
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LDateTime : TDateTime;
LInt64 : UInt64;
begin
// 変換元の値
LDateTime := StrToDateTime('2019/01/06 17:25:59');
Memo1.Lines.Clear;
// TDateTime の時刻を .NET の DateTime の値に UTC 時刻に換算して変換
LInt64 := DateTimeTodotNETTime(LDateTime, 1);
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
Memo1.Lines.Add('$' + IntToHex(LInt64, 16));
// 変換後の値を TDateTime 型の値に UTC フラグを考慮して変換
Memo1.Lines.Add('');
LDateTime := dotNETTimeToDateTime(LInt64);
Memo1.Lines.Add('$' +IntToHex(LInt64, 16));
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
// 変換後の値を TDateTime 型の値に UTC フラグを無視して変換
Memo1.Lines.Add('');
LDateTime := dotNETTimeToDateTime(LInt64, False);
Memo1.Lines.Add('$' +IntToHex(LInt64, 16));
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
end;
// Delphi の TDateTime の時刻を .NET の DateTime の値に変換
// その逆変換もテスト
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
LDateTime : TDateTime;
LInt64 : UInt64;
begin
LDateTime := StrToDateTime('2019/01/06 17:25:59');
Memo1.Lines.Clear;
// TDateTime の時刻を .NET の DateTime の値にローカル時刻にとして変換
LInt64 := DateTimeTodotNETTime(LDateTime, 2);
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
Memo1.Lines.Add('$' + IntToHex(LInt64, 16));
// 変換後の値を TDateTime 型の値に UTC フラグを考慮して変換
Memo1.Lines.Add('');
LDateTime := dotNETTimeToDateTime(LInt64);
Memo1.Lines.Add('$' +IntToHex(LInt64, 16));
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
// 変換後の値を TDateTime 型の値に UTC フラグを無視して変換
Memo1.Lines.Add('');
LDateTime := dotNETTimeToDateTime(LInt64, False);
Memo1.Lines.Add('$' +IntToHex(LInt64, 16));
Memo1.Lines.Add(FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
end;
//-----------------------------------------------------------------------------
// TDateTime 型の値を .NET の DateTime の値に変換する関数
//
// 引数の UTCFlag の値による変換結果の違い
// このフラグは .NET framework 2.0 で導入された
// 0 : そのまま変換
// 1 : 引数の時刻をローカルな時刻とみなしてUTC 時刻に換算して変換
// 2 : 引数の時刻を UTC の時刻とみなしてローカルな時刻に換算して変換
//
// TDateTime 型は倍精度実数値で 1899/12/30 が基準点
// システムファイル 時刻は 1601/01/01 が基準の 64 ビット整数値 (100 ns 単位)
// .NET の DateTime は 0001/01/01 が基準の 64 ビット整数値 (100 ns 単位)
//
// uses に DateUtils が必要
//-----------------------------------------------------------------------------
function DateTimeTodotNETTime(ADateTime: TDateTime; UTCFlag: Byte=0): UInt64;
var
LUTCFlag : Byte;
LSystemTime : TSystemTime;
LLocalFileTime : TFileTime;
LFileTime : TFileTime;
LUTCFileTime : TFileTime;
begin
LUTCFlag := UTCFlag;
if LUTCFlag > 2 then LUTCFlag := 0;
// TDateTime の時刻をシステム時刻に変換
DateTimeToSystemTime(ADateTime, LSystemTime);
// 1600年分 を加算
LSystemTime.wYear := LSystemTime.wYear + 1600;
if UTCFlag = 1 then begin
// UTC 時刻に変換して取得
SystemTimeToFileTime(LSystemTime, LLocalFileTime);
LocalFileTimeToFileTime(LLocalFileTime, LUTCFileTime);
Result := Int64(LUTCFileTime) or (UInt64(1) shl 62);
end else
if UTCFlag = 2 then begin
// ローカルな時刻に換算して取得
SystemTimeToFileTime(LSystemTime, LFileTime);
FileTimeToLocalFileTime(LFileTime, LLocalFileTime);
Result := Int64(LLocalFileTime) or (UInt64(1) shl 63);
end else begin
// 変換なし
SystemTimeToFileTime(LSystemTime, LLocalFileTime);
Result := Int64(LLocalFileTime);
end;
end;
//-----------------------------------------------------------------------------
// .NET の DateTime をローカルな時刻として TDateTime 型の値に変換する関数
// 引数の上位 2 ビットは UTC かローカルの値かのフラグ
// このフラグは .NET framework 2.0 で導入された
// ただし ChFlag の値が False の時はこの上位 2 ビットを無視して変換する
// 00 (= 0) : 指定なし
// 01 (= 1) : UTC
// 10 (= 2) : ローカル
//
// TDateTime 型は倍精度実数値で 1899/12/30 が基準点
// システムファイル 時刻は 1601/01/01 が基準の 64 ビット整数値 (100 ns 単位)
// .NET の DateTime は 0001/01/01 が基準の 64 ビット整数値 (100 ns 単位)
//
// uses に DateUtils が必要
//-----------------------------------------------------------------------------
function dotNETTimeToDateTime(AUInt64: UInt64; ChFlag: Boolean=True): TDateTime;
var
LUTCFlag : Byte;
LUInt64 : UInt64;
LSystemTime : TSystemTime;
LLocalFileTime : TFileTime;
begin
// 最上位の 2 ビットの値を取得
LUTCFlag := AUInt64 shr 62;
if not ChFlag then LUTCFlag := 0;
// 最上位の 2 ビットを 0 にした値に変換
LUInt64 := AUInt64 and $3FFFFFFFFFFFFFFF;
if LUTCFlag = 0 then begin
FileTimeToSystemTime(TFileTime(LUInt64), LSystemTime);
end else
if LUTCFlag = 1 then begin
FileTimeToLocalFileTime(TFileTime(LUInt64), LLocalFileTime);
FileTimeToSystemTime(TFileTime(LLocalFileTime), LSystemTime);
end else begin
FileTimeToSystemTime(TFileTime(LUInt64), LSystemTime);
end;
// 1600年分大きいので減算
LSystemTime.wYear := LSystemTime.wYear - 1600;
Result := SystemTimeToDateTime(LSystemTime);
end;
end.
03_ローカル時刻と協定世界時 ( UTC ) の相互変換 |
上のサンプル内に UTC (協定世界時) に変換する部分があります.
TDateTime 型の日付時刻の値を UTC の時刻に変換したり,逆に UTC の時刻をローカルの時刻に換算するだけであれば,TTimeZone クラスのプロパティやメソッドが利用できます.
|
|
図5
ローカル時刻を UTC 時刻に変換 |
リスト3
TDateTime 型におけるローカル時刻と協定世界時 ( UTC ) の相互変換 |
implementation
uses
System.DateUtils;
{$R *.dfm}
//=============================================================================
// ローカル時刻を協定世界時 (UTC) に変換
// uses に DateUtils が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LDateTime : TDateTime;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add(TTimeZone.Local.DisplayName);
Memo1.Lines.Add(TTimeZone.Local.ID);
Memo1.Lines.Add(TTimeZone.Local.Abbreviation);
LDateTime := Now;
Memo1.Lines.Add('ローカル時刻 :' + FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
LDateTime := TTimeZone.Local.ToUniversalTime(LDateTime);
Memo1.Lines.Add('協定世界時 :' + FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
end;
//=============================================================================
// 協定世界時 (UTC) をローカル時刻に変換
// uses に DateUtils が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LDateTime : TDateTime;
begin
Memo1.Lines.Clear;
LDateTime := Now;
Memo1.Lines.Add('協定世界時 :' + FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
LDateTime := TTimeZone.Local.ToLocalTime(LDateTime);
Memo1.Lines.Add('ローカル時刻 :' + FormatDateTime('yyyy/mm/dd hh:nn:ss', LDateTime));
end;
|