Delphi:如何确定空的 TDateTime 值

问题描述 投票:0回答:6

似乎无法将 NULL(或“未分配值”)分配给

TDateTime
变量。

我想象的唯一方法是使用这样的东西:

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;

有人知道不与 0 日期值重叠的更好解决方案吗?

TDateTime
值危险吗? (我的意思是,作为用于上述目的的可用资源)

delphi datetime null unassigned-variable
6个回答
21
投票

正如 Andreas 已经写的那样,

TDateTime
类型实际上是
double
,因此不可“为空”。我用

const
  c_UnassignedDate = -693594;

对于空日期值,因为这代表不可能的日期

00/00/0000
。但例如 DevExpress 使用

NullDate = -700000;
InvalidDate = NullDate + 1;

所以似乎没有一致同意的标准值,您应该选择一个适合您需要的。


12
投票

首先您需要定义“空

TDateTime
值”的含义。

A

TDateTime
值是一个双精度值,其中整数部分编码为日期,小数部分编码为时间。因此,您可以获得的最接近“空日期”的可能是
0

因此,只需测试

ADate <> 0
即可测试日期是否为“空”。

但要注意:如果你声明了一个

TDateTime
局部变量,那么在给它赋值之前它不一定是
=0
。它可以是任何东西。当然,同样的情况也适用于
integer
double
boolean
、...

类型的变量

此外,我相信具有值

TDateTime
0
编码日期 1899-12-30。

最后,负

TDateTime
值是完全正常的。例如,
-5000
对应于
1886-04-22

我不太明白你的代码的意义。如果您想使用

0
作为“未分配”值(如果您对接近 1899-12-30 的日期感兴趣,这很糟糕),为什么不简单地做

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

或者,可能(但不等同!),

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

在他的回答中,ain 为“未分配日期”值给出了一些更合理的选择。


4
投票

在库

Spring Framework for Delphi
(http://www.spring4d.org) 的单元 Spring.Persistence.Core.Session.pas 中的方法
TSession.ExecuteScalar<T>
如果结果使用值
Default(T);

为 NULL

我想,你的函数可以是这样的

function IsNull(ADate: TDateTime): Boolean;
begin
  Result := ADate = Default(TDateTime);
end;

1
投票

使用 PDateTime 代替 TDateTime,并以 nil 值发送。如果没有指向值的指针,则结果没有值。

要检查值,请使用分配的 ptr :

MyDatePointer := nil;
if ( Assigned(MyDatePointer)) then ...

1
投票

TDateTime 对于 0 到 -1 之间的值是未定义的,这意味着 -0.5 的 tDateTime 是一个未定义的值,对于空日期作为 NaN 的替代非常有用。 DateTimeToString 将显示 -0.5,与 +0.5 相同;


0
投票

System.TDateTime
的文档中所述,

TDateTime 值的整数部分是自 1899 年 12 月 30 日以来经过的天数。TDateTime 值的小数部分是一天中的时间。 […]

TDateTime 也支持负值。您应该谨慎使用负 TDateTime 值。错误使用负值会导致各种问题。

允许负值,但必须小心处理:

使用负 TDateTime 值时,计算必须单独处理时间部分。小数部分反映一天 24 小时的分数,而不考虑 TDateTime 值的符号。例如,上午 6:00 1899 年 12 月 29 日的值为 –1.25,而不是 –1 + 0.25,后者等于 –0.75。大于 -1.0 到 0.0 的日期和小于 1.0 到 0.0 的日期相互镜像。那是因为 +ve 零 和 -ve 零 相等。

到目前为止,似乎可以在代码中使用

-0.5
作为 NULL 替换。

因此,将

TDateTime
视为正常
Double
值通常不是一个好主意。一旦您的计算跨越“Delphi 纪元”(1899-12-30 00:00:00)的开始,如果不仅仅是日期(日粒度),即编码为
Integer
Double
值,结果就会出现偏差。 .

我认为这可能是一个很好的起点:

const
  NULL_DATE_TIME = TDateTime(-0.5);

function IsNullDateTime(Value: TDateTime): Boolean;
begin
  Result := Value = NULL_DATE_TIME;
end;

我在这里的双重比较中故意不使用 epsilon,因为 -0.5 完美地以 IEEE-754 格式表示,并且正常的

TDateTime
值永远不应该达到 -1 和 0 之间的区间(不包含)。

但是,我不太确定我的最后一个断言:我手头只有过时的 C++Builder 6,并且

IncDay(TDateTime(0.5),-1)
不幸的是返回了这个值。我希望这个错误现在已经修复了。

我现在测试的是当前的Lazarus版本没有出现这个bug。

© www.soinside.com 2019 - 2024. All rights reserved.