Delphi 捐赠日的变体误报

Delphi 捐赠日的变体误报,delphi,variant,Delphi,Variant,(背景)我有一个程序,它使用参数化查询在一天中的某个时间搜索数据库。所需的功能意味着我在一天结束时进行一些搜索,因此我有如下代码 Query.Parameters[3].Value := TimeOf(EnfOfTheDay(ToTime)); 由于时间为“31/12/1899”,因此此操作失败并出现格式错误。以下控制台程序可证明这一点,该程序在系统控制台上输出“31/12/1899”(或区域设置中的等效值) 这很容易解决,但我的问题是这是否是一个应该向Embarcadero报告的错误。我可以

(背景)我有一个程序,它使用参数化查询在一天中的某个时间搜索数据库。所需的功能意味着我在一天结束时进行一些搜索,因此我有如下代码

Query.Parameters[3].Value := TimeOf(EnfOfTheDay(ToTime));
由于时间为“31/12/1899”,因此此操作失败并出现格式错误。以下控制台程序可证明这一点,该程序在系统控制台上输出“31/12/1899”(或区域设置中的等效值)

这很容易解决,但我的问题是这是否是一个应该向Embarcadero报告的错误。我可以看到,当TDateTime类型中的纯时间值存储到一个变量中,然后强制转换为文本时,就会出现问题。在一天中的早些时候,会产生类似“23:59”的细线


如果我将时间变量更改为TTime,则生成的字符串是数字分数(即变量尚未设置为datetime值),但我不明白为什么等于23:59:59(这是EndOfTheDay生成的)的特定分数被解释为1899日期。我天生就怀疑任何能产生1899个展期日期的东西,因为Microsoft产品的特殊问题可能意味着这是故意的。

变量表示将设置为
varDate
,这在内部是一个
TDateTime
变量。因此,信息仍然保存在变体中

WriteLn(Output, FormatDateTime('hh:nn:ss',V)); 
输出

23:59:59

可在最终调用以下函数的变量例程中找到错误:

function DateToWStrViaOS(const AValue: TDateTime): WideString;
begin
  VarResultCheck(VarBStrFromDate(AValue, VAR_LOCALE_USER_DEFAULT, 0, Result),
                 varDate, varOleStr);
end;
VarBStrFromDate
是对操作系统的调用,它以某种方式将值舍入到
1
,因此日期为“31/12/1899”


结论:如果您仍然希望在数据库中使用变体,请不要使用变体库提供的
TDateTime
的内置变体到文本转换



更新:
EndOfTheDay
将返回午夜前1毫秒的时间。转换为文本时的变体分辨率似乎基于秒(windows设计)。将时间设置为1,然后用
时间:=inc毫秒(时间,-501)
进行减法将返回正确的值。(或
Time:=IncSecond(Time,-1)
,如果您愿意。)

如果您将示例改写为

begin
    Time := Now; //TimeOf(EndOfTheDay(EncodeDate(2017,1,26)));
    Time := EndOfTheDay(Time);
    V := Time;
    WriteLn(Output, V);
    Time := TimeOf(Time);
    V := Time;
    WriteLn(Output, V);
    ReadLn;
end.
在时间变量上放置一个手表,并在调试器中单步执行,很明显,是调用
TimeOf
导致了无效结果。原因如我写这篇文章时出现的LU RD的答案所示,但后来被删除了(如果它再次出现,我会记下来),即
TimeOf
将日期时间值的整数部分设置为零,默认情况下表示为“31/12/1899”。但依我看,这并不是问题的原因:问题在于将
TimeOf
上的结果分配给一个变量,并将其留给RTL生成其表示

回到最初提示q的问题,如果db的SQL实现支持,那么解决这个问题的更好方法可能是使用一个构造/函数,该构造/函数只处理时间组件,不管它的日期/时间是如何存储的


顺便说一句,我认为你的q标题是错误的,问题不是“endoftheday的变量错误陈述”。

您可以通过使用.Asxxxx函数来设置参数值,而不是使用.values来避免变量。您实际上应该避免使用TimeOf函数,而只使用FormatDateTime函数,因此实际答案是操作系统API VarBStrFromDate正在执行此操作错误的转换,这绝对不是Delphi的问题。请参阅我的更新,windows在转换为文本时会舍入到最接近的秒数。
begin
    Time := Now; //TimeOf(EndOfTheDay(EncodeDate(2017,1,26)));
    Time := EndOfTheDay(Time);
    V := Time;
    WriteLn(Output, V);
    Time := TimeOf(Time);
    V := Time;
    WriteLn(Output, V);
    ReadLn;
end.