5
votes

Is it possible to express an empty (zero) TDateTime value as a constant? I tried TDateTime(0), TDateTime(0.0) and other things, but the compiler (Delphi 7) wasn't impressed.

At the moment I'm using an initialised global variable:

const
   TDateTime_0: TDateTime = 0.0;

This sort of works. However, I just inherited a nice big pile of Delphi 7 code and I haven't used Turbo Pascal in ages... Which means I seriously need to brush up my Delphi fu, and this makes me want to know.

By contrast, the compiler is perfectly happy with something like Integer(0). Its assignment to a variant results in a value of 0 of type ftInteger, whereas assigning a plain literal 0 would result in a variant of type ftSmallInt.

Clarification: the objective is to pass an 'empty' value of a specific type to functions that take variants (which includes the compiler-managed variant arrays known as 'array of const' and also the setters for things like TParameter.Value).

Clarification for Ken White: the issue here is essentially type deduction and overload resolution; above-mentioned 'functions that take variants' are just a special case. The literals 0 and 0.0 are implicitly convertible to TDateTime, which is why they can be assigned to receptacles of that type (variables, record fields) and they can be used to initialise such receptacles (i.e. function parameters) without further ado. However, things change when the compiler needs to do type deduction:

procedure foo (value: Double); overload; 
procedure foo (value: TDateTime); overload;

The underlying type is Double in both cases, which means that the compiler requires arguments to be typed explicitly (i.e. calls with plain literals are rejected as ambiguous). With ordinal-based types the explicit typing is no problem but type Double is problematic and requires values to be stuffed into typed receptacles before they can be used. Compilable example (requires a Delphi that's a bit newer than Delphi 7):

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;

My question is/was simply whether it is possible to form expressions of type TDateTime (or other types based on Double) in the same way as it is possible for Integer and TSomeId in the example above, without allocating and initialising a typed memory location for that purpose. However, Yuriy's answer indicates that this is only possible for ordinal types.

2
I was asking about a compile-time constant expression that is tagged with the type TDateTime the same way that Integer(0) is of type Integer instead of SmallInt as a plain ('untyped') literal 0 would be. I deliberately avoided the term 'typed constant` since Borland/Embarcadero lore uses that for read-only initialised variables, which is not the same thing. The exact type of an expression - constant or otherwise - is relevant in contexts where the compiler needs to do type deduction; assignment to (or initialisation of) variants is one such case, overload resolution is another.DarthGizka
@KenWhite basically he complains about Delphi violating its own type x = TYPE y construct that should make a totally unrelated type with no implicit typecasting. Kind of similar to my complain stackoverflow.com/questions/11029353Arioch 'The
@DarthGizka I believe you could try do it in more recent Delphi with Advanced Records + Operators Overloading namely implicit type-cast. If your record would have implicit inline typecasts to/from TDateTime but not to/from double than maybe - maybe - it could work. However Delphi 7 is far too old for those concepts. Dunno about FPC/Lazarus/CodeTyphonArioch 'The
Your last edit makes the question much more clear. Thanks for doing so. :-)Ken White

2 Answers

3
votes

Compiler is OK with casting ordinal types to other ordinal types, but refuses to cast floating-point types to each other, even if they are exact the same:

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

What exactly do you want? If this TDateTime constant is needed just to pass it to some function requiring TDateTime, then you can just pass 0.0 and it will work:

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

There are 2 functions which could be handy:

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

It checks boundaries for Value and if it's all right, makes single assignment.

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

This one explicitly creates DateTime variant. I tried them both in code like this, they work the same:

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

Code like this may be a little more understandable than using TDateTime_0 constant, but it's a little more bulky.

-5
votes

Set the Date to 'gg' This will set the date to blank.