【问题标题】:How know type variable is TDateTime, TDate and TTime in DelphiDelphi中如何知道类型变量是DateTime、Date和Time
【发布时间】:2013-10-03 17:02:09
【问题描述】:

我需要知道类型变量 TDateTime、TDate 和 TTime。

有人知道怎么做吗?

我用下面的代码,结果是“Is NOT TDateTime”,“Is NOT TDate”,“Is NOT Ttime”


program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.Rtti,
  System.SysUtils;

var
  DateTime, Date,Time: TValue;

begin

  DateTime:= StrToDateTime( '01/01/2013 01:05:09' );
  if ( DateTime.TypeInfo = System.TypeInfo(TDateTime) ) then
    Writeln( 'Is TDateTime' )
  else
    Writeln( 'Is NOT TDateTime' );

  Date:=  StrToDate( '01/01/2015' );
  if ( Date.TypeInfo = System.TypeInfo(TDate) ) then
    Writeln( 'Is TDate' )
  else
    Writeln( 'Is NOT TDate' );

 Time:=  StrToTime( '01:01:02' );
  if ( Date.TypeInfo = System.TypeInfo(TTime) ) then
    Writeln( 'Is TTime' )
  else
    Writeln( 'Is NOT TTime' );

 Readln;

end.

谢谢

【问题讨论】:

  • 也许你可以尝试关注答案from here
  • 欢迎来到 Stack Overflow。将您预期获得的结果包含在内非常好,但报告您获得的结果而不是也很有帮助。您知道您没有获得 TDateTime,因此请进一步调查并找出您获得的类型。另请注意,StrToDateTime、StrToDate 和 StrToTime 返回 TDateTime,因此不要对区分它们抱有太大希望。
  • 类型始终为TDateTime
  • 不,类型总是Extended - 请参阅下面的答案。

标签: delphi rtti tdatetime


【解决方案1】:

TValueImplicit 运算符重载得到了你。

当您将StrToDateTimeStrToDateStrToTime 的结果分配给TValue 时,它使用TValue 中最匹配的Implicit 运算符重载,即Extended

另外请记住,所有三个函数都返回 TDateTime,因此即使 TDateTimeTDateTTime 存在运算符重载,它也不会按预期工作。

要获得正确的结果,您必须在将值分配给 TValue 变量时明确指定类型:

DateTime := TValue.From<TDateTime>(StrToDateTime( '01.01.2013 01:05:09' ));

Date:= TValue.From<TDate>(StrToDate( '01.01.2015' ));

Time:= TValue.From<TTime>(StrToTime( '01:01:02' ));

【讨论】:

  • 哇,Extended!我无法克服新的 Emba RTL 代码仍然使用Extended 的事实。将日期时间放入Extended 简直是疯了。将它们存储在二进制浮点(!!)中已经够糟糕了。呸!
  • “问题”是浮点数的 TValue 的唯一匹配隐式运算符重载 is Extended 破坏了 TDateTime/TTime/TDate/任何其他浮点类型的兼容性(即之后能够确定类型)。虽然它主要表现为这些类型,但对于在 TValue 中没有特定隐式运算符重载但与具有重载的任何类型的赋值兼容的任何其他类型也是如此。
  • 我喜欢任何抱怨 Extended 不应该存在的机会,而 TDateTime 是浮点数。一个机会同时抱怨太诱人了,不能错过! ;-)
【解决方案2】:

以防万一您试图确定 StrToDateTime 的结果类型:

type
  TDateType = (dtDate, dtDateTime, dtTime);

function getDateType(date: TDateTime): TDateType;
begin
  if Trunc(date) = date then // Or DateOf(date), if available
  begin
    Result := dtDate;
  end
  else
  begin
    if Trunc(date) = 0 then // Or DateOf(date), if avaialble
    begin
      Result := dtTime
    end
    else
    begin
      Result := dtDateTime;
    end;
  end;
end;

// Sample
var
  result: TDateType;
begin
  result := getDateType(StrToDateTime('01/01/2013 01:05:09')); // dtDateTime
  result := getDateType(StrToDateTime('01/01/2015')); // dtDate
  result := getDateType(StrToDateTime('01:01:02')); // dtTime
  // One caveat
  result := getDateType(StrToDateTime('01/01/2013 00:00:00')); // dtDate
end;

或者,您可以使用TryStrToDateTryStrToTimeTryStrToDateTime 函数。

【讨论】:

  • 使用DateOf更具描述性
  • @DavidHeffernan,我同意,如果有的话。
【解决方案3】:

如果您好奇,TDateTime 在内部被编码为浮点 Double

TDateTime 内部结构
小数部分表示时间,整数部分表示日期。
知道这一点后,以下测试将评估为true

dtTime: ABS(Double(DateTime1)) < 1.0 
dtDate: Trunc(Double(DateTime1)) = Double(DateTime1)
dtDateTime:  (     (ABS(Double(DateTime1)) > 1.0) 
         and (Trunc(Double(DateTime1)) <> Double(DateTime1)) )

显然,这是一种非常迂回的测试方式,但有时它有助于了解 TDateTime 在内部是如何形成的。

DateUtils
这些测试的合理版本是:

uses DateUtils;

dtDate: DateTime1 = DateOf(DateTime1)
dtTime: DateTime1 = TimeOf(DateTime1)
dtDateTime:(DateTime1 <> DateOf(DateTime1)) and (DateTime1 <> TimeOf(DateTime1))

TDateTime 与 Excel 兼容
0 链接到 Microsoft Excel 中的时代:1899 年 12 月 30 日; 12:00 A.M.
(应该是 1-1-1900,但他们更改了它以弥补 Lotus 123 日期算法中的错误)
这很好,因为 Delphi 的 TDateTime 与 Excel 的 DateTime 完全兼容。

这是官方文档:http://docwiki.embarcadero.com/Libraries/XE5//en/System.TDateTime

【讨论】:

  • "没有负日期!"显然我们没有相同的约会经历。 ;-)
  • 您无法选择是否使用 -ve 日期 - 您要么需要表示 1900 年前的日期,要么不需要。不过,我可以看到时间段可能会令人困惑。
  • @MattAllwood 当然你可以自己推出,但不要指望 RTL​​ 支持 (DateToStr) 等。哦,1900 年前的日期很复杂。参见维基百科。
  • -1 表示没有负日期。有而且它们的功能非常好。您链接的文档甚至明确指出 -1.25 是 1899 年 12 月 29 日;上午6:00。现在应该 -1.25 + 0.25 加起来是多少? ...嗯,当然是-1。是的,这正好提前 6 小时:1989 年 12 月 30 日午夜。没什么复杂的。完全和完全正常。这是意料之中的,否则我们将永远无法对 1989 年 12 月 30 日之前的日期做任何事情,而且家谱程序不会在 Delphi 中编写任何业务
  • 更正。我承认在用时间分数进行计算时会有点复杂。时间在零的两侧从零开始增加,这似乎“关闭”,因为您会期望时间分数从左到右移动,就像日期甚至低于零一样。事实上,时间分数的增加与日期“相反”实际上是为了使计算正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-22
  • 1970-01-01
  • 2012-09-04
  • 2012-09-02
  • 1970-01-01
  • 2012-09-19
相关资源
最近更新 更多