当天结束时的变体失实陈述

  • 本文关键字:陈述 结束 delphi variant
  • 更新时间 :
  • 英文 :


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

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年展期的事情都持怀疑态度,这可能意味着这是故意的。

变量表示将设置为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毫秒的时间。当转换为文本时,变体分辨率似乎是基于秒的(窗口设计)。将时间设置为1并用Time := IncMilliSecond(Time,-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.

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

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

顺便说一句,我认为你的q标题是错误的,问题不在于"当天结束时的变体失实陈述"。

相关内容

  • 没有找到相关文章

最新更新