20

Seems there is no way to assign NULL (either an "unassigned value" to TDateTime variables.

The only way I've imagined is using something like this:

function isNull(aDate : TDateTime) : boolean;
const NullDate = 0.0;
var aNullDate : TDatetime;
    ms : Int64;
begin
  aNullDate := NullDate;
  ms := MilliSecondsBetween(aDate,aNullDate);
  result := (ms = Int64(0));
end;

Is there anybody out who knows better solution what not overlaps 0 date value?

Are negative TDateTime values dangerous? (As an able resource for previous purpose)

Fabrizio
  • 7,603
  • 6
  • 44
  • 104
xsubira
  • 474
  • 1
  • 5
  • 14
  • If you intend to use this function the was I think, surely `NullDate` should be a global constant? – Andreas Rejbrand Feb 20 '13 at 16:59
  • I've experienced problems when comparing a zero assigned value TDateTime variable to the const value 0. A _simple_ **if** as this one didn't check the condition ` var v_datetime: TDatetime;` ` v_datetime := 0;` ` if (v_datetime = 0) then actionToTake` – xsubira Feb 20 '13 at 17:30
  • 3
    That is because of floating-point fuzz. Use `Math.IsZero`. – Andreas Rejbrand Feb 20 '13 at 17:32
  • 0 is a perfectly valid date, and negative dates are perfectly fine as well. 0 is midnight on 30 Dec 1899. Negative numbers are dates before that. – Nick Hodges Feb 20 '13 at 21:03

5 Answers5

20

As Andreas already wrote, the TDateTime type is actually double and thus not "nullable". I use

const
  c_UnassignedDate = -693594;

for a empty date value as this represents an impossible date of 00/00/0000. But for example DevExpress uses

NullDate = -700000;
InvalidDate = NullDate + 1;

So there seems to be no agreed upon standard vale, you should pick one which suits your need.

ain
  • 22,394
  • 3
  • 54
  • 74
  • 2
    There is no date where **day** and **month** are 0 (zero). In database, if the date is unassigned then `NULL` should be used, not some magic date. – ain Feb 20 '13 at 16:51
  • 1
    Yeah, sorry. Taking back, I was looking just at the year portion of that date... Well, if the value of a certain date time column will be `NULL` and I would have to store this value strictly to a `TDateTime` field, I would probably use your `c_UnassignedDate` constant value. [+1] – TLama Feb 20 '13 at 17:00
  • How do you figure that -693594 represents the date 0/0/0000? – Rob Kennedy Feb 20 '13 at 18:05
  • 1
    @Rob: I guess because `-693591` represents `0000-01-03`, `-693592` represents `0000-01-02`, and `-693593` represents `0000-01-01`, at least according to `DateTimeToStr`. – Andreas Rejbrand Feb 20 '13 at 18:16
  • @RobKennedy just do `ShowMessage(FormatDateTime('dd.mm.yyyy',-693594));` and it pops up dlg with `00.00.0000`. – ain Feb 20 '13 at 19:47
  • @ain: As does every smaller value. My analysis shows that -693594 is the greatest negative integer with this property. – Andreas Rejbrand Feb 20 '13 at 19:52
11

First you need to define what you mean by 'an empty TDateTime value'.

A TDateTime value is a double with the date encoded in the integer part and the time encoded in the fractional part. So, the closest thing to a 'null date' you can get is probably 0.

Hence, simply test ADate <> 0 to test if the date is 'null'.

But beware: if you declare a TDateTime local variable then it will not necessarily be =0 before you give it a value. It can be anything. Of course, the same thing applies to variables of type integer, double, boolean, ...

Also, I believe that a TDateTime with value 0 encodes the date 1899-12-30.

Finally, negative TDateTime values are perfectly normal. For instance, -5000 corresponds to 1886-04-22.

I don't quite get the point of your code. If you want to use 0 as the 'unassigned' value (which is bad if you are interested in dates close to 1899-12-30), why not do simply

function IsUnassigned(ADate: TDateTime): boolean;
begin
  result := ADate = 0;
end;

or, possibly (but not equivalently!),

function IsUnassigned(ADate: TDateTime): boolean;
begin
  result := IsZero(Date);
end;

In his answer, ain gave a couple of more reasonable choices for the 'unassigned date' value.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
3

At unit Spring.Persistence.Core.Session.pas of library Spring Framework for Delphi (http://www.spring4d.org) in method TSession.ExecuteScalar<T> in case of NULL for result used value Default(T);

I think, Your function can look like

function IsNull(ADate: TDateTime): Boolean;
begin
  Result := ADate = Default(TDateTime);
end;
Nashev
  • 490
  • 4
  • 10
1

Use PDateTime instead TDateTime, and send as nil value. If no pointer to value, result no value.

To check value use Assigned ptr :

MyDatePointer := nil;
if ( Assigned(MyDatePointer)) then ...
Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
1

tDateTime is undefined for the values between 0 and -1 which means that a tDateTime of -0.5 is an undefined value and useful for a null date as an alternative to NaN. DateTimeToString will display -0.5 the same as +0.5;