StrToDate 无法转换从 DateToStr 获得的值
StrToDate cannot convert value obtained from DateToStr
我有一个旧应用程序。它的数据中存储了一个本地化格式的日期。该字符串仅用于显示,因此以本地化形式存在是可以接受的。
现在我们需要将其重新用作 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 引发异常 class EConvertError,消息为“28。 9. 2017'不是有效日期'。
这是不正确的,异常提到的日期是有效的!它是刚才通过 DateToStr 生成的。
这对我来说完全没有意义。
这可能是 Windows 10 中的错误吗?
如果我在 OS 的区域设置中输入 dd. M.yyyy
作为短日期格式,我可以重复你的问题。或者 dd. M. yyyy
要获得您在问题中引用的确切错误消息,请注意格式字符串中的 spaces。
StrToDate
失败的原因是"sysutils.pas"中的ScanDate
函数失败,returns错误。 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
和上述函数,与失败原因无关, returns 默认日期分隔符“/”。所以这是 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;
但是您不能将返回的 '. '
分配给 TFormatSettings
的 DateSeparator
,因为它需要一个 Char。你必须假装你知道分隔符是 '.'
并使用它,这只有效,因为第二个字符是 space ,它在 ScanDate
.
中被剥离
我有一个旧应用程序。它的数据中存储了一个本地化格式的日期。该字符串仅用于显示,因此以本地化形式存在是可以接受的。 现在我们需要将其重新用作 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 引发异常 class EConvertError,消息为“28。 9. 2017'不是有效日期'。 这是不正确的,异常提到的日期是有效的!它是刚才通过 DateToStr 生成的。 这对我来说完全没有意义。 这可能是 Windows 10 中的错误吗?
如果我在 OS 的区域设置中输入 dd. M.yyyy
作为短日期格式,我可以重复你的问题。或者 dd. M. yyyy
要获得您在问题中引用的确切错误消息,请注意格式字符串中的 spaces。
StrToDate
失败的原因是"sysutils.pas"中的ScanDate
函数失败,returns错误。 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
和上述函数,与失败原因无关, returns 默认日期分隔符“/”。所以这是 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;
但是您不能将返回的 '. '
分配给 TFormatSettings
的 DateSeparator
,因为它需要一个 Char。你必须假装你知道分隔符是 '.'
并使用它,这只有效,因为第二个字符是 space ,它在 ScanDate
.