diff --git a/components/fpspreadsheet/source/common/fpsnumformat.pas b/components/fpspreadsheet/source/common/fpsnumformat.pas
index 8cf6c5f16..3f70b0872 100644
--- a/components/fpspreadsheet/source/common/fpsnumformat.pas
+++ b/components/fpspreadsheet/source/common/fpsnumformat.pas
@@ -161,12 +161,14 @@ type
by the number format parser from a format string. }
TsNumFormatParams = class(TObject)
private
+ FAllowLocalizedAMPM: Boolean;
protected
function GetNumFormat: TsNumberFormat; virtual;
function GetNumFormatStr: String; virtual;
public
{@@ Array of the format sections }
Sections: TsNumFormatSections;
+ constructor Create;
procedure DeleteElement(ASectionIndex, AElementIndex: Integer);
procedure InsertElement(ASectionIndex, AElementIndex: Integer;
AToken: TsNumFormatToken);
@@ -175,6 +177,7 @@ type
procedure SetDecimals(AValue: Byte);
procedure SetNegativeRed(AEnable: Boolean);
procedure SetThousandSep(AEnable: Boolean);
+ property AllowLocalizedAMPM: boolean read FAllowLocalizedAMPM write FAllowLocalizedAMPM;
property NumFormat: TsNumberFormat read GetNumFormat;
property NumFormatStr: String read GetNumFormatStr;
end;
@@ -315,7 +318,8 @@ function BuildNumberFormatString(ANumberFormat: TsNumberFormat;
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
AMinIntDigits: Integer = 1): String;
-function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
+function BuildFormatStringFromSection(const ASection: TsNumFormatSection;
+ AllowLocalizedAMPM: Boolean = true): String;
function ApplyTextFormat(AText: String; AParams: TsNumFormatParams): String;
function ConvertFloatToStr(AValue: Double; AParams: TsNumFormatParams;
@@ -1118,9 +1122,7 @@ end;
{==============================================================================}
{@@ ----------------------------------------------------------------------------
- Adds an AM/PM format code to a pre-built time formatting string. The strings
- replacing "AM" or "PM" in the final formatted number are taken from the
- TimeAMString or TimePMString of the specified FormatSettings.
+ Adds an AM/PM format code to a pre-built time formatting string.
@param ATimeFormatString String of time formatting codes (such as 'hh:nn')
@param AFormatSettings FormatSettings for locale-dependent information
@@ -1130,13 +1132,8 @@ end;
-------------------------------------------------------------------------------}
function AddAMPM(const ATimeFormatString: String;
const AFormatSettings: TFormatSettings): String;
-var
- am, pm: String;
- fs: TFormatSettings absolute AFormatSettings;
begin
- am := IfThen(fs.TimeAMString <> '', fs.TimeAMString, 'AM');
- pm := IfThen(fs.TimePMString <> '', fs.TimePMString, 'PM');
- Result := Format('%s %s/%s', [StripAMPM(ATimeFormatString), am, pm]);
+ Result := Format('%s AM/PM', [StripAMPM(ATimeFormatString)]);
end;
{@@ ----------------------------------------------------------------------------
@@ -1470,9 +1467,15 @@ end;
@param ASection Parsed section of number format elements as created by the
number format parser
- @return Excel-compatible format string
+ @param AllowLocalizedAMPM Replaces "AMPM" in a time format string by "AM/PM".
+ "AMPM" is allowed by FPS, but not by Excel. When converting a time to
+ string it is replaced by the localized strings
+ FormatSettings.TimeAMString/.TimePMString.
+
+ @return Excel-compatible format string
-------------------------------------------------------------------------------}
-function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
+function BuildFormatStringFromSection(const ASection: TsNumFormatSection;
+ AllowLocalizedAMPM: Boolean = true): String;
var
element: TsNumFormatElement;
i, n: Integer;
@@ -1542,7 +1545,12 @@ begin
else Result := Result + DupeString('s', element.IntValue);
nftMilliseconds:
Result := Result + DupeString('0', element.IntValue);
- nftSign, nftSignBracket, nftExpChar, nftExpSign, nftAMPM, nftDateTimeSep:
+ nftAMPM:
+ if Lowercase(element.TextValue) = 'ampm' then
+ Result := Result + 'AM/PM'
+ else if element.TextValue <> '' then
+ Result := Result + element.TextValue;
+ nftSign, nftSignBracket, nftExpChar, nftExpSign, nftDateTimeSep:
if element.TextValue <> '' then Result := Result + element.TextValue;
nftCurrSymbol:
if element.TextValue <> '' then
@@ -2189,6 +2197,12 @@ end;
{ TsNumFormatParams }
{==============================================================================}
+constructor TsNumFormatParams.Create;
+begin
+ inherited;
+ FAllowLocalizedAMPM := true;
+end;
+
{@@ ----------------------------------------------------------------------------
Deletes a parsed number format element from the specified format section.
@@ -2249,7 +2263,7 @@ begin
if Length(Sections) > 0 then begin
Result := BuildFormatStringFromSection(Sections[0]);
for i := 1 to High(Sections) do
- Result := Result + ';' + BuildFormatStringFromSection(Sections[i]);
+ Result := Result + ';' + BuildFormatStringFromSection(Sections[i], FAllowLocalizedAMPM);
end else
Result := '';
end;
diff --git a/components/fpspreadsheet/source/common/fpsreaderwriter.pas b/components/fpspreadsheet/source/common/fpsreaderwriter.pas
index 6bc65c480..c54af67f7 100644
--- a/components/fpspreadsheet/source/common/fpsreaderwriter.pas
+++ b/components/fpspreadsheet/source/common/fpsreaderwriter.pas
@@ -152,8 +152,6 @@ type
procedure AddBuiltinNumFormats; virtual;
function FindNumFormatInList(ANumFormatStr: String): Integer;
-// function FixColor(AColor: TsColor): TsColor; virtual;
- procedure FixFormat(ACell: PCell); virtual;
procedure GetSheetDimensions(AWorksheet: TsBasicWorksheet;
out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal); virtual;
procedure ListAllNumFormats; virtual;
@@ -624,21 +622,6 @@ begin
Result := -1;
end;
-{@@ ----------------------------------------------------------------------------
- If formatting features of a cell are not supported by the destination file
- format of the writer, here is the place to apply replacements.
- Must be overridden by descendants, nothin happens here. See BIFF2.
-
- @param ACell Pointer to the cell being investigated. Note that this cell
- does not belong to the workbook, but is a cell of the
- FFormattingStyles array.
--------------------------------------------------------------------------------}
-procedure TsCustomSpreadWriter.FixFormat(ACell: PCell);
-begin
- Unused(ACell);
- // to be overridden
-end;
-
{@@ ----------------------------------------------------------------------------
Determines the size of the worksheet to be written. VirtualMode is respected.
Is called when the writer needs the size for output. Column and row count
diff --git a/components/fpspreadsheet/source/common/xlscommon.pas b/components/fpspreadsheet/source/common/xlscommon.pas
index 43d11db32..484f67f50 100644
--- a/components/fpspreadsheet/source/common/xlscommon.pas
+++ b/components/fpspreadsheet/source/common/xlscommon.pas
@@ -418,6 +418,11 @@ type
function GetLocalLinks(AWorksheet: TsBasicWorksheet): TsBiffExternSheetList;
end;
+ TsExcelNumFormatParser = class(TsNumFormatParser)
+ protected
+ function BuildFormatString: String; override;
+ end;
+
{ TsSpreadBIFFReader }
TsSpreadBIFFReader = class(TsCustomSpreadReader)
@@ -1062,6 +1067,20 @@ begin
end;
+{ FPS can use an "ampm" modifier in the time format string, Excel cannot.
+ The function replaces is by "AM/PM". }
+function TsExcelNumFormatParser.BuildFormatString: String;
+var
+ p: Integer;
+begin
+ Result := inherited;
+ if IsTimeFormat or IsDateTimeFormat then begin
+ p := pos('ampm', Lowercase(Result));
+ if p > 0 then Result := Copy(Result, 1, p-1) + 'AM/PM';
+ end;
+end;
+
+
{------------------------------------------------------------------------------}
{ TsBIFFDefinedName }
{------------------------------------------------------------------------------}
@@ -4357,7 +4376,7 @@ begin
for i:= FFirstNumFormatIndexInFile to NumFormatList.Count-1 do
begin
fmtStr := NumFormatList[i];
- parser := TsNumFormatParser.Create(fmtStr, Workbook.FormatSettings);
+ parser := TsExcelNumFormatParser.Create(fmtStr, Workbook.FormatSettings);
try
fmtStr := parser.FormatString;
WriteFORMAT(AStream, fmtStr, i);
diff --git a/components/fpspreadsheet/source/common/xlsxml.pas b/components/fpspreadsheet/source/common/xlsxml.pas
index 35b54aa3d..e7a0facfb 100644
--- a/components/fpspreadsheet/source/common/xlsxml.pas
+++ b/components/fpspreadsheet/source/common/xlsxml.pas
@@ -1823,6 +1823,7 @@ begin
if (uffNumberFormat in fmt^.UsedFormattingFields) then
begin
nfp := book.GetNumberFormat(fmt^.NumberFormatIndex);
+ nfp.AllowLocalizedAMPM := false; // Replace "AMPM" by "AM/PM"
AppendToStream(AStream, Format(INDENT3 +
'' + LF, [UTF8TextToXMLText(nfp.NumFormatStr)]));
end;
diff --git a/components/fpspreadsheet/source/common/xlsxooxml.pas b/components/fpspreadsheet/source/common/xlsxooxml.pas
index 60e537170..35c6be988 100644
--- a/components/fpspreadsheet/source/common/xlsxooxml.pas
+++ b/components/fpspreadsheet/source/common/xlsxooxml.pas
@@ -3363,7 +3363,7 @@ begin
for i:= FFirstNumFormatIndexInFile to NumFormatList.Count-1 do
begin
numFmtStr := NumFormatList[i];
- parser := TsNumFormatParser.Create(numFmtStr, Workbook.FormatSettings);
+ parser := TsExcelNumFormatParser.Create(numFmtStr, Workbook.FormatSettings);
try
numFmtStr := UTF8TextToXMLText(parser.FormatString);
xmlStr := xmlStr + Format('',