Delphi:如何表示空的TDateTime?

5

能否用一个常量表示空(零)TDateTime值呢?我尝试过 TDateTime(0), TDateTime(0.0) 等等,但是编译器(Delphi 7)并不认可。

目前我使用一个已初始化的全局变量:

const
   TDateTime_0: TDateTime = 0.0;

这种方法基本可行。但是,我刚继承了一大堆Delphi 7的代码,而我已经很久没有使用Turbo Pascal了...这意味着我需要认真恢复我的Delphi技能,这让我想知道更多。
相比之下,编译器对于Integer(0)这样的内容非常满意。它被分配给变体后,结果为类型为ftInteger的值0,而将普通文字0分配给变体会导致一个类型为ftSmallInt的变体。
澄清一下:目标是传递特定类型的“空”值给接受变体的函数(包括编译器管理的变体数组,即“array of const”,以及像TParameter.Value这样的设置器)。
针对Ken White的说明:这里的问题基本上是类型推断和重载分辨率;上述“接受变体的函数”只是一个特殊情况。文字0和0.0可以隐式转换为TDateTime,这就是为什么它们可以分配给该类型的容器(变量、记录字段),并且它们可以用于初始化此类容器(即函数参数)而无需进一步操作。然而,当编译器需要进行类型推断时,情况就会发生变化。
procedure foo (value: Double); overload; 
procedure foo (value: TDateTime); overload;

在这两种情况下,底层类型都是Double,这意味着编译器要求参数必须显式地指定类型(即使用纯文本字面量的调用将被拒绝为模棱两可)。对于基于序数的类型,显式类型不是问题,但类型Double是有问题的,需要将值塞入类型化的容器中才能使用。以下是可编译的示例(需要一个比Delphi 7更新一点的Delphi版本):

type
   TSomeId = type Integer;

procedure foo (value: Integer  ); overload;  begin  WriteLn('Integer   ', value);  end;
procedure foo (value: TSomeId  ); overload;  begin  WriteLn('TSomeId   ', value);  end;
procedure foo (value: Double   ); overload;  begin  WriteLn('Double    ', value);  end;
procedure foo (value: TDateTime); overload;  begin  WriteLn('TDateTime ', value);  end;

procedure test_TYPE_Double;
var
   d: Double;
   t: TDateTime;
begin
   foo(Integer(0));
   foo(TSomeId(0));
   d := 0;  foo(d);
   t := 0;  foo(t);
end;

我的问题很简单,就是是否可以像上面例子中的IntegerTSomeId一样,在不分配和初始化类型化内存位置的情况下,以相同的方式形成基于Double的其他类型或TDateTime类型的表达式。然而,Yuriy的答案表明这只适用于序数类型。


我询问的是编译时常量表达式,其类型标记为 TDateTime,就像 Integer(0) 与普通(“未标记”)字面值 0 的类型不同一样。我故意避免使用“有类型常量”这个术语,因为 Borland/Embarcadero 的传统用法是指只读初始化变量,这并不是同一回事。一个表达式 - 常量或其他 - 的确切类型在编译器需要进行类型推导的上下文中是相关的;对变体的赋值(或初始化)就是这种情况之一,重载分辨率是另一种情况。 - DarthGizka
1
@KenWhite基本上他抱怨Delphi违反了自己的type x = TYPE y结构,这应该创建一个完全不相关的类型,没有隐式类型转换。有点类似于我的抱怨https://dev59.com/6mgu5IYBdhLWcg3w2ahm - Arioch 'The
1
@DarthGizka 我相信你可以尝试在更近期的Delphi中使用高级记录+运算符重载,即隐式类型转换。如果你的记录具有从TDateTime到double的隐式内联类型转换,但没有从double到TDateTime的隐式内联类型转换,那么也许 - 也许 - 它可以工作。 然而,Delphi 7对于这些概念来说太过陈旧。不知道FPC/Lazarus/CodeTyphon如何。 - Arioch 'The
你最后的编辑让问题更加清晰易懂。感谢你这么做。 :-) - Ken White
2个回答

3

编译器允许将一个序数类型强制转换为另一个序数类型,但即使它们完全相同,拒绝将浮点数类型强制转换为彼此:

TMyOwnDouble = type double;
...
var a,b: TMyOwnDouble;
...
a:=MyOwnDouble(0.0); //invalid typecast
b:=0.0;  //no problem

你需要什么?如果只是为了传递TDateTime常量给某些需要TDateTime的函数,请直接传递0.0,它也可以正常工作:

caption:=DateTimeToStr(0.0); //it shows 30.12.1899

有两个函数可能会很有用:

function FloatToDateTime(const Value: Extended): TDateTime; //sysUtils unit

它检查 Value 的边界,如果一切正常,则进行单独赋值。

function VarFromDateTime(DateTime: TDateTime): Variant;  //Variants unit

这个代码明确创建了DateTime变量。 我在代码中尝试了这两种方式,它们的效果相同:

var V: Variant;
...
V:=VarFromDateTime(0.0);
//V:=FloatToDateTime(0.0);  //works as well
Caption:=V;  //shows 0:00:00

像这样编写代码可能比使用TDateTime_0常量更易于理解,但它会使代码变得更加冗长。


这适用于参数类型为TDateTime的函数,但不适用于使用变量的函数。我已经在我的问题中添加了相应的澄清。无论如何+1 :-) - DarthGizka
谢谢Yuriy。你提到的这两个函数非常方便,因为它们在调用时非常明确地表明了意图(就像“自我记录源代码”一样)。 - DarthGizka
浮点转换被认为是无效的,因为太多来自 C 或 C++ 的人希望 Double(MyInteger) 将整数转换为双精度浮点数,而不是实际发生的位重新解释。在此之前,这些转换是有效的。我认为这在非常早期的 Delphi 版本或甚至 Turbo/Borland Pascal 中已经改变了。 - Rudy Velthuis

-5

将日期设置为'gg' 这将把日期设置为空白。


4
在回答问题之前,我认为你应该了解问题中使用的标签或语言。如果你不清楚问题,最好不要试图回答它。请确保熟悉相关标签和语言。我不认为你对此很熟悉。 - Ken White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接