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