一天结束的变体虚假陈述

Variant misrepresentation for endoftheday

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

Query.Parameters[3].Value := TimeOf(EnfOfTheDay(ToTime));

这会因格式错误而失败,因为时间显示为“31/12/1899”。以下控制台程序演示了这一点,该程序在系统控制台(或区域设置中的等效项)上输出“31/12/1899”。

program Project1;
{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils, System.DateUtils;
var
  V: variant;
  Time: TDateTime;
begin
    Time := TimeOf(EndOfTheDay(EncodeDate(2017,1,26)));
    V := Time;
    Write(Output, V);
    ReadLn;
end.

这很容易变通,但我的问题是这是否是一个应该报告给 Embarcadero 的故障。我可以看到,当 TDateTime 类型中的仅时间值存储到变体中,然后将其强制转换为文本时,就会出现此问题。当天早些时候的时间可以很好地产生像“23:59”这样的字符串。

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

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

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

产出

23:59:59

在最终调用的变体 VarToStr 例程中发现错误:

function DateToWStrViaOS(const AValue: TDateTime): WideString;
begin
  VarResultCheck(VarBStrFromDate(AValue, VAR_LOCALE_USER_DEFAULT, 0, Result),
                 varDate, varOleStr);
end;

VarBStrFromDate 是对 OS 的调用,它以某种方式将值四舍五入为 1,因此日期为“31/12/1899”。


结论,如果您仍想在数据库中使用变体,请不要使用变体库提供的 built-in 变体到 TDateTime 的文本转换。


更新:EndOfTheDay 将 return 午夜前 1 毫秒的时间。似乎转换为文本时的变体分辨率是基于秒的(windows 设计)。将时间设置为 1 并用 Time := IncMilliSecond(Time,-501) 减去 return 将得到正确的值。 (如果你愿意,也可以 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.

观察 Time 变量并在调试器中 single-step 它,显然是对 TimeOf 的调用导致了无用的结果。原因如我在写这篇文章时出现的LU RD的回答中所指出的,但后来被删除了(如果它再次出现我会把它记下来),即 TimeOf 将日期时间值的整数部分设置为零,默认表示为“31/12/1899”。但在我看来,这个原因不是问题所在:问题是将 TimeOf 上的结果分配给一个变体,然后将其留给 RTL 来产生它的表示。

回到最初提示您 q 的问题,如果您的数据库的 SQL 实现支持它,可能是解决此问题的更好方法,是使用 construct/function 处理仅存储其 dates/times 的时间分量。

顺便说一句,我认为你的问题是错误的,问题不在于'variant misrepresentation for endoftheday'。