问题
A third party component (FastReports) on my application is using extensively the System.Variants.VarToWideStr function, which is fine except that it ignores the regional settings I need that application to use.
Example:
FormatSettings.ShortDateFormat := 'dd/mm/yyyy';
ShowMessage(VarToWideStr(Date));
FormatSettings.ShortDateFormat := 'yyyy/mm/dd';
ShowMessage(VarToWideStr(Date));
This code always returns the same string, ignoring the regional settings that I indicate the application to use.
Do you know of another way to change the regional settings that the application (concretely VarToWideStr) is going to use ?.
回答1:
I think you're screwed by awful design of Variants unit as well as FastReport. VarToWideStr
calls VarToWideStrDef
which invokes implicit _VarToWStr
, then DateToWStrViaOS
and finally VarBStrFromDate
from unit System.VarUtils
.
In fact VarBStrFromDate
is a reference to function and its implementation depends on compiler. On Windows 32/64 this is just a reference to VarBstrFromDate from oleaut32.dll
. Non-Windows compilers fall back to converting the value via DateTimeToStr
(single argument invariant) which uses global format settings and 'C' format specifier to format the value.
There is no good way around that, because all those routines depend too much on global state. Luckily (??) you can point VarBStrFromDate
to your own implementation. You can get inspired by default implementation for non-Windows platforms seen in function BackupVarBStrFromDate
of unit System.VarUtils
. Then you can do something like this:
uses
System.SysUtils, System.Variants, System.VarUtils, System.DateUtils;
function MyVarBstrFromDate(dateIn: TDateTime; LCID: Integer; dwFlags: Integer;
out bstrOut: WideString): HRESULT; stdcall;
begin
if LCID = VAR_LOCALE_USER_DEFAULT then
begin
bstrOut := DateTimeToStr(dateIn);
Result := VAR_OK;
end
else
Result := VAR_NOTIMPL;
end;
{ ... }
System.VarUtils.VarBstrFromDate := MyVarBstrFromDate;
FormatSettings.ShortDateFormat := 'yyyy-mm-dd';
FormatSettings.LongTimeFormat := 'hh:nn:ss';
Writeln(VarToWideStr(EncodeDate(2019, 11, 29)));
Writeln(VarToWideStr(EncodeDateTime(2019, 11, 29, 10, 30, 50, 700)));
to get the result:
2019-11-29
2019-11-29 10:30:50
You need to be aware that this changes the behavior of all routines that rely on VarBstrFromDate
throughout the entire application.
The same goes for VarToStr
. See also here, where the author suggest extracting the date value from variant before conversion to string.
来源:https://stackoverflow.com/questions/59100960/change-the-regional-settings-format-for-sysem-variants-vartowidestr