StrToDate无法转换从DateToStr获得的值

时间:2017-09-28 15:01:10

标签: windows delphi delphi-10.1-berlin

我有一个旧申请。它具有存储在其数据中的本地化格式的日期。此字符串仅用于显示,因此可以将其置于本地化表单中。 现在我们需要将它重用为TDateTime。这似乎很简单:因为我们从DateToStr获取了字符串,我们将使用StrToDate将其转换回来。所以我写了一个小的控制台程序来验证它:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;
var
  S:String;
  D: TDateTime;
begin
  S := DateToStr(Now);
  Writeln(S);
  D := StrToDate(S); //! throws an EConvertError
  Readln;
end.

抛出一个EConvertError: 项目Project1.exe引发了异常类EConvertError,消息为'' 28。 9. 2017'不是有效日期'。 这是不正确的,异常提到的日期是有效的!它刚刚通过DateToStr生成。 这对我来说完全没有意义。 这可能是Windows 10中的错误吗?

1 个答案:

答案 0 :(得分:5)

如果我在操作系统的区域设置中输入dd. M.yyyy短日期格式,我可以复制您的问题。或者dd. M. yyyy要在问题中引用您引用的确切错误消息,请注意格式字符串中的空格。

StrToDate失败的原因是“sysutils.pas”中的ScanDate函数失败并返回False。 ScanDate失败的原因是默认格式设置记录中的日期分隔符不正确。

RTL使用以下代码检索日期分隔符,其中为LOCALE_SDATE参数传递LocaleType,并为Default参数传递“/”。

...
var
  Buffer: array[0..1] of Char;
begin
  if GetLocaleInfo(Locale, LocaleType, Buffer, 2) > 0 then
    Result := Buffer[0] else
  Result := Default;

对于您的日期格式,所需的缓冲区为3个字符,因为RTL仅提供2个字符,API失败并显示ERROR_INSUFFICIENT_BUFFER,上述函数与失败原因无关,返回默认日期分隔符“/”。所以这是Delphi RTL中的一个错误。

如果您的奇数格式字符串具有有效用例,请使用接收格式设置参数的StrToDate重载。如果没有,只需在区域设置中更正日期字符串。

很遗憾,您无法为第一种替代方案应用通用解决方案。也就是说,您可以使用例如:

来检索正确的日期分隔符
function GetDateSeparator: string;
var
  NumChars: Integer;
begin
  NumChars := GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, nil, 0);
  Win32Check(NumChars <> 0);
  SetLength(Result, NumChars);
  Win32Check(GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, PChar(Result), NumChars) <> 0);
  SetLength(Result, Length(Result) - 1);
end;

但是您无法将返回的'. '分配给DateSeparator的{​​{1}},因为它需要Char。你必须假装你知道分隔符是TFormatSettings并使用它,并且这只能起作用,因为第二个字符是在'.'中被剥离的空格。