我有一个旧申请。它具有存储在其数据中的本地化格式的日期。此字符串仅用于显示,因此可以将其置于本地化表单中。 现在我们需要将它重用为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中的错误吗?
答案 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
并使用它,并且这只能起作用,因为第二个字符是在'.'
中被剥离的空格。