首页 > 解决方案 > 更改 Sysem.Variants.VarToWideStr 的区域设置格式

问题描述

我的应用程序上的第三方组件 (FastReports) 广泛使用 System.Variants.VarToWideStr 函数,这很好,只是它忽略了我需要该应用程序使用的区域设置。

例子:

FormatSettings.ShortDateFormat := 'dd/mm/yyyy';
ShowMessage(VarToWideStr(Date));
FormatSettings.ShortDateFormat := 'yyyy/mm/dd';
ShowMessage(VarToWideStr(Date));

此代码始终返回相同的字符串,忽略我指示要使用的应用程序的区域设置。

您是否知道另一种更改应用程序(具体是 VarToWideStr)将要使用的区域设置的方法?

标签: delphidate-formattingdelphi-10.1-berlin

解决方案


我认为您被变体单元和 FastReport 的糟糕设计搞砸了。VarToWideStr调用VarToWideStrDef隐式_VarToWStr,然后DateToWStrViaOS最后VarBStrFromDate从 unit调用System.VarUtils

实际上VarBStrFromDate是对函数的引用,它的实现依赖于编译器。在 Windows 32/64 上,这只是对VarBstrFromDate的引用oleaut32.dll。非 Windows 编译器回退到通过DateTimeToStr(单参数不变量)转换值,它使用全局格式设置和“C”格式说明符来格式化值。

没有好的方法可以解决这个问题,因为所有这些例程都过多地依赖于全局状态。幸运的是(??)你可以指向VarBStrFromDate你自己的实现。BackupVarBStrFromDate您可以从unit函数中看到的非 Windows 平台的默认实现中获得灵感System.VarUtils。然后你可以做这样的事情:

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)));

得到结果:

2019-11-29
2019-11-29 10:30:50

您需要注意,这会改变依赖于VarBstrFromDate整个应用程序的所有例程的行为。

也是如此VarToStr。另请参阅此处,作者建议在转换为字符串之前从变量中提取日期值。


推荐阅读