StrToDate无法转换从DateToStr获得的值

Lub*_*bos 0 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.
Run Code Online (Sandbox Code Playgroud)

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

Ser*_*yuz 5

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

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

RTL使用以下代码检索日期分隔符,其中LOCALE_SDATELocaleType参数传递,并为参数传递"/" Default.

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

在您的日期格式的情况下,所需的缓冲区是3个字符,因为RTL仅提供API失败的2个字符,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;
Run Code Online (Sandbox Code Playgroud)

但你不能指定返回'. 'DateSeparatorTFormatSettings,因为它需要一个字符.你必须假装你知道分隔符是a '.'并使用它,这只能起作用,因为第二个char是一个被剥离的空间ScanDate.