一天结束的变体虚假陈述
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'。
(背景)我有一个程序在一天中的时间搜索数据库时使用参数化查询。所需的功能意味着我在一天结束时进行一些搜索,所以我自然有如下代码
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'。