【问题标题】:TryStrToDateTime ignores trailing characters in string ("false positive")TryStrToDateTime 忽略字符串中的尾随字符(“误报”)
【发布时间】:2019-02-03 11:09:50
【问题描述】:

我正在编写一个数据导入实用程序来将数据导入数据库应用程序。可以从剪贴板(例如从 Excel)或文件中检索数据,并且最初存储在 TStringlist 中。在下一步中,用户可以选择适当的列分隔符(制表符、逗号等)。将数据拆分为列后(使用选定的分隔符),每个字符串值(我们称之为单元格值)都会根据适用的数据库字段类型检查有效性。

我遇到的问题是日期时间值(可能还有日期和/或时间值,但我还没有检查过)。如果用户选择了“错误”的分隔符,则数据不会被拆分,并且每一行都包含一列(当然这是正确的)。在这种情况下,单元格值可能包含如下所示的字符串(我正在显示调试值以显示正确的分隔符,在这种情况下为制表符):

'04/01/10 00:00'#9'2.50'#9'100'#9'文本值'

当使用 TryStrToDateTime 或 StrToDatetime 时,该字符串值“通过”,因为字符串被“剪裁”(即忽略尾随文本并返回正确的日期时间值 04/01/10)。如果我在稍后阶段将单元格值(原始字符串)作为变量传递给范围比较函数,它显然会因 EVariantTypeCastError 而失败。

是否有方法(或现有的 Delphi RTL 函数)来检查字符串值是否仅包含有效的日期(时间)(即没有尾随文本)?考虑到这一点,找不到函数(或函数参数),我也一直在考虑检查字符串长度,但我的软件在国际上使用,因此日期时间格式会有所不同,因此可能有不同的长度。

PS:我在这里添加了下面的示例代码,因为我无法将它添加到我的 cmets。

procedure TForm1.Button1Click(Sender: TObject);
var
  lStrVal: string;
  lIsDateTime: boolean;
  lDateTimeVal: TDateTime;
begin

  lStrVal := '01/01/2019 10:00' + chr(9) + '120.00' + chr(9) + 'Some text';

  lIsDateTime := TryStrToDateTime(lStrVal, lDateTimeVal);

  if lIsDateTime then
    messageDlg('String value is a date/time! ' + #13#10 + 'String: ' + lStrVal + #13#10 + 'Date/time is: ' + DateTimeToStr(lDateTimeVal), mtInformation, [mbOK], 0)
  else
    messageDlg('String value cannot be converted to a date/time!', mtWarning, [mbOK], 0);
end;

【问题讨论】:

  • 您似乎忽略了TryStrToDateTime() 的返回值(布尔值),因为它使用您的测试字符串返回False,尽管TDateTime 值可能是正确的。因此,您也不会检测到真正的日期时间错误。但是,如果您对此感到满意,那么您也拥有您所要求的功能。只需将您获得的日期时间转换回字符串,以便去除原始字符串中日期时间之后的任何垃圾?
  • @TomBrunberg;其实我并没有忽略返回值。请考虑我添加到问题中的代码。您必须相信我的话,返回值为“真”。
  • 那么,也许Delphi版本有区别。我用的是XE7,你用的是什么?
  • 德尔福 10.3 Rio。您是说该函数在 XE7 中正常工作(即返回 false)吗?
  • @TomBrunberg,由于某些原因,尾随字符被忽略。您看到的是日期时间格式不适合您的语言环境设置。只需输入一个有效的日期时间字符串,后跟一些额外的不相关字符,该函数将返回 true。

标签: string validation datetime delphi


【解决方案1】:

似乎解决方案(至少对于我的应用程序而言)是结合 TryStrToDateTime 和 TryStrToDate。为了演示,启动一个新的 VCL 应用程序并在表单上放置一个 ListBox 和 TButton(保留标准名称)。将以下代码粘贴到 TButton OnClick 处理程序中:

var
  lDateVal, lDateTimeVal: TDateTime;
  lStrVal: string;
  lResult: boolean;
begin
  ListBox1.Items.Clear;

  lStrVal := '01/01/2019 10:00' + '-120.00' + '-Some text';
  ListBox1.Items.Add('String value : ' + lStrVal);

  lDateVal := EncodeDate(2000, 1, 1);
  lDateTimeVal := EncodeDate(2000, 1, 1) + EncodeTime(1, 0, 0, 0);

  lResult := TryStrToDate(lStrVal, lDateVal);
  if lResult then
    ListBox1.Items.Add(' - TryStrToDate : TRUE')
  else
    ListBox1.Items.Add(' - TryStrToDate : FALSE');
  ListBox1.Items.Add('DateTime value: ' + DateTimeToStr(lDateVal));

  lResult := TryStrToDateTime(lStrVal, lDateTimeVal);
  if lResult then
    ListBox1.Items.Add(' - TryStrToDateTime : TRUE')
  else
    ListBox1.Items.Add(' - TryStrToDateTime : FALSE');
  ListBox1.Items.Add('DateTime value: ' + DateTimeToStr(lDateTimeVal));

  // Reset
  lDateVal := EncodeDate(2000, 1, 1);
  lDateTimeVal := EncodeDate(2000, 1, 1) + EncodeTime(1, 0, 0, 0);

  lResult := TryStrToDateTime(lStrVal, lDateTimeVal) and TryStrToDate(lStrVal, lDateVal);
  if lResult then
    ListBox1.Items.Add(' - Combined : TRUE')
  else
    ListBox1.Items.Add(' - Combined : FALSE');
  ListBox1.Items.Add('DateTime value: ' + DateTimeToStr(lDateTimeVal));

  ListBox1.Items.Add('');
  lStrVal := '01/01/2019 10:00';
  ListBox1.Items.Add('String value : ' + lStrVal);

  lResult := TryStrToDateTime(lStrVal, lDateTimeVal) and TryStrToDate(lStrVal, lDateVal);
  if lResult then
    ListBox1.Items.Add(' - Combined : TRUE')
  else
    ListBox1.Items.Add(' - Combined : FALSE');

  try
    lDateTimeVal := VarToDateTime(lStrVal);
    lResult := true;
  except
    lResult := false;
  end;

  if lResult then
    ListBox1.Items.Add(' - Using Variant : TRUE')
  else
    ListBox1.Items.Add(' - Using Variant : FALSE');

这给我留下了一个问题,如果这意味着 TryStrToDateTime 与 TryStrToDate 相比实施不正确?至少,功能的“设计”似乎存在矛盾; “字符串值一个日期”与“字符串值一个日期时间开始”。除非我遗漏了什么……

【讨论】:

  • FWIW;我已经在我的答案中编辑了代码,因为将 TryStrToDateTime 和 TryStrToDate 结合起来的解决方案不起作用。例如; TryStrToDate 将在 '01/01/2019 00:00' 失败,这是一个有效的 DateTime!经过一些试验和错误,我想出了一个尝试例外的 VarToDateTime。对我来说,这似乎现在可以按要求工作了......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-30
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多