OLE Excel 输出中的国际日期格式问题

Posted

技术标签:

【中文标题】OLE Excel 输出中的国际日期格式问题【英文标题】:International date formatting issues in OLE Excel output 【发布时间】:2013-06-05 17:18:16 【问题描述】:

在我目前使用的一个产品中,Excel 电子表格是使用 Delphi 的 OLE 生成的。电子表格包括许多日期,应用程序从系统设置中加载短日期格式并将其应用于单元格。除非系统格式设置为至少俄语、巴什基尔语、鞑靼语、雅库特语、哈萨克语和乌兹别克语之一(可能还有其他我没有尝试过),否则这非常有效。

代码是-

xlws.Cells[irow,icol] := ActivityData.Target_Date;
xlvalidrange := xlws.Range[xlws.Cells[irow,icol],xlws.Cells[irow,icol]];
xlvalidrange.NumberFormat:= LocShortDateFormat;

在这种情况下(在调试时)ActivityData.Target_Date 是 41192,这是 Excel 存储日期和时间的格式,LocShortDateFormat 等于“dd.MM.yyyy”。这与 Windows 中显示的俄语商店日期格式相匹配,并使用代码以编程方式检索-

LocShortDateFormat := ShortDateFormat;

用这种格式打开电子表格会显示消息-

Excel 在 Spreadsheet.xlsx 中发现不可读的内容是否要恢复此工作簿的内容?

执行此操作后,数据将简单地显示为数字 41192,单元格中没有格式。更奇怪的是,手动应用“dd.MM.yyyy”的格式字符串,然后在单元格中显示“dd.MM.yyyy”来代替数据。

这同样适用于任何标准的日期/时间字符串格式化字符。可以通过选择“日期”类别和对应的类型作为格式手动将数据更改为日期格式,然后正确显示,因此这不是数据的问题,而是格式字符串的问题。

手动选择正确日期格式时 Excel 使用的格式化字符串是 ДД.ММ.ГГГГ - 手动更改调试时使用的格式化字符串会在生成的电子表格中产生正确的输出,并且不可读的内容消息会消失。

奇怪的中文、日语、塞尔维亚语和马其顿语(作为非英语字符集语言的示例)都可以使用标准的日期/时间格式字符。

在 Excel 本身中,标准字符似乎无法正常工作,即使电子表格是新的并且不是以编程方式创建的,即从 Excel 应用程序中创建的新电子表格。

既然如此,这似乎不是 Delphi 或 Windows 的问题(C# Windows 表单即使使用俄罗斯语言环境也可以使用标准字符正确格式化日期没有问题),但它仍然存在如何获取返回的问题Delphi 中正确的格式化字符串。

我并不热衷于对已知有问题的语言环境进行一系列条件“if”语句测试,但根据我迄今为止所做的研究,这似乎是解决问题的唯一方法。

有没有办法让 Excel 通过 OLE 使用本地日期格式而不提供格式化字符串,或者获取 Excel 用于在该本地化中格式化日期的字符串,以便以正确的格式提供字符串?

【问题讨论】:

【参考方案1】:

是的,您可以使用 Excel 应用程序实例上的 International 属性获取各种国际化/本地化字符和字符串。后期绑定示例:

function GetExcel_International(const aExcel: OleVariant; const aIndex: Integer): string;
begin
  try
    Result := aExcel.International[aIndex];
  except
    ...
  end;
end;

我们使用它来获取构成格式化字符串的各种字符:

ExcelYearCharacter := GetExcel_International(FExcelApplication, xlYearCode);
ExcelMonthCharacter := GetExcel_International(FExcelApplication, xlMonthCode);
ExcelDayCharacter := GetExcel_International(FExcelApplication, xlDayCode);
ExcelHourCharacter := GetExcel_International(FExcelApplication, xlHourCode);
ExcelMinuteCharacter := GetExcel_International(FExcelApplication, xlMinuteCode);

然后我们使用这些从 Windows 转换为 Excel 格式:

function ConvertWindowsLocalDateStringToExcel(const aString: string): string;
begin
  Result := StringReplace(aString, UpperCase(WindowsYearCharacter),
            UpperCase(ExcelYearCharacter), [rfReplaceAll]);
  Result := StringReplace(Result, LowerCase(WindowsYearCharacter),
            LowerCase(ExcelYearCharacter), [rfReplaceAll]);

  Result := StringReplace(Result, UpperCase(WindowsMonthCharacter),
            UpperCase(ExcelMonthCharacter), [rfReplaceAll]);
  Result := StringReplace(Result, LowerCase(WindowsMonthCharacter),
            LowerCase(ExcelMonthCharacter), [rfReplaceAll]);

  Result := StringReplace(Result, UpperCase(WindowsDayCharacter),
            UpperCase(ExcelDayCharacter), [rfReplaceAll]);
  Result := StringReplace(Result, LowerCase(WindowsDayCharacter),
            LowerCase(ExcelDayCharacter), [rfReplaceAll]);
end;

所有xl... 常量都来自我们自己的单元之一,但您也应该能够在早期绑定的 Delphi OLE 服务器包装器中找到它们。例如,在 Delphi / RAD Studio 安装的 ...\OCX\Servers 文件夹中的 ExcelXP 单元中。

有关Application.International 属性的更多信息,请访问: http://msdn.microsoft.com/en-us/library/office/bb177675(v=office.12).aspx

【讨论】:

一个出色而完整的答案,我假设 WindowsDayCharacter 等也是您在应用程序中定义的常量? @pwdst:实际上它们是变量,但它们在实现部分中声明并且永远不会改变......推理?不知道,不在那里... :-)【参考方案2】:

我的解决方案如下:

首先我创建一个TDate 类型的var。 然后我从表中填写var,然后插入它,如下所示:

var
  tReportDate : TDate;

....<br><br>
    tReportDate := FieldByName('DateReport').AsDateTime;<br>
    ExcelApp.Cells[StartColumnid, 1].Value := tReportDate;

这解决了我的情况。这是一个国际项目,被各种地点使用。

希望这能有所帮助。

【讨论】:

以上是关于OLE Excel 输出中的国际日期格式问题的主要内容,如果未能解决你的问题,请参考以下文章

excel改的日期格式为啥要双击一下单元格才能变

如何将EXCEL表格中的出生日期格式快速转换?

在Excel里,日期为啥变成了数字

在excel中日期格式如何转换成常规格式?

如何使用POI处理Excel中的日期数据类型

excel改的日期格式为啥要双击一下单元格才能变