【问题标题】:Variant misrepresentation for endofthedayendoftheday 的变体虚假陈述
【发布时间】:2017-01-26 11:42:24
【问题描述】:

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

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 年的日期。我天生就怀疑任何产生 1899 翻转日期的东西,因为 Microsoft 产品的特殊问题可能意味着这是故意的。

【问题讨论】:

  • 您可以通过使用 .Asxxxx 函数来设置参数值而不是使用 .Value 来避免变体
  • 您实际上应该避免使用 TimeOf 函数,而只使用 FormatDateTime 函数

标签: delphi variant


【解决方案1】:

变体表示将设置为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 是对操作系统的调用,它以某种方式将值四舍五入为1,因此日期为“31/12/1899”。


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


更新:EndOfTheDay 将返回午夜前 1 毫秒的时间。转换为文本时的变体分辨率似乎基于秒(Windows 设计)。将时间设置为 1 并减去 Time := IncMilliSecond(Time,-501) 将返回正确的值。 (或者Time := IncSecond(Time,-1),如果你愿意的话。)

【讨论】:

  • 所以实际的答案是操作系统 API VarBStrFromDate 进行了错误转换,这绝对不是 Delphi 问题。
  • 查看我的更新,windows 在转换为文本时会四舍五入到最接近的秒数。
【解决方案2】:

如果您将示例重写为

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 变量并在调试器中单步执行它,很明显是对 TimeOf 的调用导致了无用的结果。原因如 LU RD 的回答所示,该回答在我写这篇文章时出现,但后来被删除(如果它再次出现,我将把它记下来),即 TimeOf 将日期时间值的整数部分设置为零,默认情况下表示为“31/12/1899”。但这个原因不是,imo,问题:问题是将TimeOf 上的结果分配给一个变体,并将其留给 RTL 来生成它的表示。

回到你的问题,它首先提示你的 q,如果你的数据库的 SQL 实现支持它,可能是解决这个问题的更好方法,是使用一个构造/函数,它只处理它的时间组件日期/时间被存储。

顺便说一句,我认为您的 q 标题是错误的,问题不在于“对结束的变体虚假陈述”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-13
    • 2022-06-24
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多