fpspreadsheet: Fix some date/time format display issues for ods.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3202 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
0650a4a5b4
commit
888f605851
@ -19,6 +19,7 @@ var
|
||||
MyDir: string;
|
||||
number1, number2, number3, number4,
|
||||
number5, number6, number7, number8: Double;
|
||||
dt1, dt2: TDateTime;
|
||||
row: Integer = 7;
|
||||
begin
|
||||
MyDir := ExtractFilePath(ParamStr(0));
|
||||
@ -31,6 +32,9 @@ begin
|
||||
number7 := 1/number3;
|
||||
number8 := -1/number3;
|
||||
|
||||
dt1 := EncodeDate(2012, 1, 1) + EncodeTime(9, 1, 2, 12);
|
||||
dt2 := EncodeDate(2012, 12, 1) + EncodeTime(21, 1, 2, 12);
|
||||
|
||||
// Create the spreadsheet
|
||||
MyWorkbook := TsWorkbook.Create;
|
||||
MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
|
||||
@ -230,6 +234,65 @@ begin
|
||||
MyWorksheet.WriteCurrency(row, 6, number6, nfAccountingRed, 2, 'EUR', pcfCSV, ncfMCSV);
|
||||
MyWorksheet.WriteCurrency(row, 7, number7, nfAccountingRed, 2, 'EUR', pcfCSV, ncfMCSV);
|
||||
MyWorksheet.WriteCurrency(row, 8, number8, nfAccountingRed, 2, 'EUR', pcfCSV, ncfMCSV);
|
||||
inc(row,2);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'Some date/time values in various formats:');
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfShortDateTime');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfShortDateTime);
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfShortDateTime);
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfShortDate');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfShortDate);
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfShortDate);
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfLongDate');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfLongDate);
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfLongDate);
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfShortTime');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfShortTime);
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfShortTime);
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfLongTime');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfLongTime);
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfLongTime);
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfShortTimeAM');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfShortTimeAM);
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfShortTimeAM);
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfLongTimeAM');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfLongTimeAM);
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfLongTimeAM);
|
||||
inc(row);
|
||||
// In order to use a semicolon as a date-time separator it must be escaped either by
|
||||
// using the backslash or quotes (because the semicolon is the separator between sections)
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfCustom, dddd, dd/mm/yyyy\; hh:nn');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfCustom, 'dddd, dd/mm/yyyy\; hh:nn');
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfCustom, 'dddd, dd/mm/yyyy\; hh:nn');
|
||||
MyWorksheet.WriteUTF8Text(row, 3, 'The semicolon must be escaped otherwise it would be misunderstood as a section separator.');
|
||||
MyWorksheet.WriteUTF8Text(row, 4, 'This format is not displayed correctly by Open/LibreOffice.');
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfCustom, dddd, dd/mm/yyyy"; "hh:nn');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfCustom, 'dddd, dd/mm/yyyy"; "hh:nn');
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfCustom, 'dddd, dd/mm/yyyy"; "hh:nn');
|
||||
MyWorksheet.WriteUTF8Text(row, 3, 'The semicolon must be escaped otherwise it would be misunderstood as a section separator.');
|
||||
MyWorksheet.WriteUTF8Text(row, 4, 'This format is not displayed correctly by Open/LibreOffice.');
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfCustom, dd/mmm');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfCustom, 'dd/mmm');
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfCustom, 'dd/mmm');
|
||||
MyWorksheet.WriteUTF8Text(row, 3, 'The slash is replaced by the date or time separator of the FormatSettings');
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfCustom, mmm/yy');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfCustom, 'mmm/yy');
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfCustom, 'mmm/yy');
|
||||
MyWorksheet.WriteUTF8Text(row, 3, 'The slash is replaced by the date or time separator of the FormatSettings');
|
||||
inc(row);
|
||||
MyWorksheet.WriteUTF8Text(row, 0, 'nfCustom, mmm-yy');
|
||||
MyWorksheet.WriteDateTime(row, 1, dt1, nfCustom, 'mmm-yy');
|
||||
MyWorksheet.WriteDateTime(row, 2, dt2, nfCustom, 'mmm-yy');
|
||||
MyWorksheet.WriteUTF8Text(row, 3, 'The dash is used literally');
|
||||
|
||||
// Creates a new worksheet
|
||||
MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet 2');
|
||||
|
@ -275,12 +275,16 @@ function TsNumFormatParser.AnalyzeCurrency(const AValue: String): Boolean;
|
||||
var
|
||||
uValue: String;
|
||||
begin
|
||||
uValue := Uppercase(AValue);
|
||||
Result := (uValue = Uppercase(AnsiToUTF8(FWorkbook.FormatSettings.CurrencyString))) or
|
||||
(uValue = '$') or (uValue = 'USD') or
|
||||
(uValue = '€') or (uValue = 'EUR') or
|
||||
(uValue = '£') or (uValue = 'GBP') or
|
||||
(uValue = '¥') or (uValue = 'JPY');
|
||||
if (FWorkbook = nil) or (FWorkbook.FormatSettings.CurrencyString = '') then
|
||||
Result := false
|
||||
else begin
|
||||
uValue := Uppercase(AValue);
|
||||
Result := (uValue = Uppercase(AnsiToUTF8(FWorkbook.FormatSettings.CurrencyString))) or
|
||||
(uValue = '$') or (uValue = 'USD') or
|
||||
(uValue = '€') or (uValue = 'EUR') or
|
||||
(uValue = '£') or (uValue = 'GBP') or
|
||||
(uValue = '¥') or (uValue = 'JPY');
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Creates a formatstring for all sections.
|
||||
@ -1528,6 +1532,11 @@ begin
|
||||
end;
|
||||
'A', 'a':
|
||||
ScanAMPM;
|
||||
',', '-':
|
||||
begin
|
||||
Addelement(nftText, FToken);
|
||||
FToken := NextToken;
|
||||
end
|
||||
else
|
||||
// char pointer must be at end of date/time mask.
|
||||
FToken := PrevToken;
|
||||
|
@ -343,9 +343,9 @@ begin
|
||||
AIsTimeOnly := false;
|
||||
case Elements[el].IntValue of
|
||||
1: s := '';
|
||||
2: s := 'number:style="long"';
|
||||
3: s := 'number:textual="true"';
|
||||
4: s := 'number:style="long" number:textual="true"';
|
||||
2: s := 'number:style="long" ';
|
||||
3: s := 'number:textual="true" ';
|
||||
4: s := 'number:style="long" number:textual="true" ';
|
||||
end;
|
||||
Result := result + AIndent +
|
||||
' <number:month ' + s + '/>' + LineEnding;
|
||||
@ -357,11 +357,9 @@ begin
|
||||
AIsTimeOnly := false;
|
||||
case Elements[el].IntValue of
|
||||
1: s := 'day ';
|
||||
2: s := 'day number:style="long"';
|
||||
3: s := 'day number:textual="true"';
|
||||
4: s := 'day number:style="long" number:textual="true"';
|
||||
5: s := 'day-of-week ';
|
||||
6: s := 'day-of-week number:style="long"';
|
||||
2: s := 'day number:style="long" ';
|
||||
3: s := 'day-of-week ';
|
||||
4: s := 'day-of-week number:style="long" ';
|
||||
end;
|
||||
Result := Result + AIndent +
|
||||
' <number:' + s + '/>' + LineEnding;
|
||||
@ -1581,57 +1579,47 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
||||
end else
|
||||
if nodeName = 'number:year' then begin
|
||||
s := GetAttrValue(node, 'number:style');
|
||||
if s = 'long' then fmt := fmt + 'yyyy'
|
||||
else if s = '' then fmt := fmt + 'yy';
|
||||
fmt := fmt + IfThen(s = 'long', 'yyyy', 'yy');
|
||||
end else
|
||||
if nodeName = 'number:month' then begin
|
||||
s := GetAttrValue(node, 'number:style');
|
||||
stxt := GetAttrValue(node, 'number:textual');
|
||||
if (stxt = 'true') then begin // Month as text
|
||||
if (s = 'long') then fmt := fmt + 'mmmm' else fmt := fmt + 'mmm';
|
||||
end else begin // Month as number
|
||||
if (s = 'long') then fmt := fmt + 'mm' else fmt := fmt + 'm';
|
||||
end;
|
||||
if (stxt = 'true') then // Month as text
|
||||
fmt := fmt + IfThen(s = 'long', 'mmmm', 'mmm')
|
||||
else // Month as number
|
||||
fmt := fmt + IfThen(s = 'long', 'mm', 'm');
|
||||
end else
|
||||
if nodeName = 'number:day' then begin
|
||||
s := GetAttrValue(node, 'number:style');
|
||||
stxt := GetAttrValue(node, 'number:textual');
|
||||
if (stxt = 'true') then begin // day as text
|
||||
if (s = 'long') then fmt := fmt + 'dddd' else fmt := fmt + 'ddd';
|
||||
end else begin // day as number
|
||||
if (s = 'long') then fmt := fmt + 'dd' else fmt := fmt + 'd';
|
||||
end;
|
||||
end;
|
||||
fmt := fmt + IfThen(s = 'long', 'dd', 'd');
|
||||
end else
|
||||
if nodeName = 'number:day-of-week' then begin
|
||||
s := GetAttrValue(node, 'number:stye');
|
||||
if (s = 'long') then fmt := fmt + 'dddddd' else fmt := fmt + 'ddddd';
|
||||
s := GetAttrValue(node, 'number:style');
|
||||
fmt := fmt + IfThen(s = 'long', 'dddd', 'ddd');
|
||||
end else
|
||||
if nodeName = 'number:hours' then begin
|
||||
s := GetAttrValue(node, 'number:style');
|
||||
if (sovr = 'false') then begin
|
||||
if (s = 'long') then fmt := fmt + '[hh]' else fmt := fmt + '[h]';
|
||||
end else begin
|
||||
if (s = 'long') then fmt := fmt + 'hh' else fmt := fmt + 'h';
|
||||
end;
|
||||
if (sovr = 'false') then
|
||||
fmt := fmt + IfThen(s = 'long', '[hh]', '[h]')
|
||||
else
|
||||
fmt := fmt + IfThen(s = 'long', 'hh', 'h');
|
||||
sovr := '';
|
||||
end else
|
||||
if nodeName = 'number:minutes' then begin
|
||||
s := GetAttrValue(node, 'number:style');
|
||||
if (sovr = 'false') then begin
|
||||
if (s = 'long') then fmt := fmt + '[nn]' else fmt := fmt + '[n]';
|
||||
end else begin
|
||||
if (s = 'long') then fmt := fmt + 'nn' else fmt := fmt + 'n';
|
||||
end;
|
||||
if (sovr = 'false') then
|
||||
fmt := fmt + IfThen(s = 'long', '[nn]', '[n]')
|
||||
else
|
||||
fmt := fmt + IfThen(s = 'long', 'nn', 'n');
|
||||
sovr := '';
|
||||
end else
|
||||
if nodeName = 'number:seconds' then begin
|
||||
s := GetAttrValue(node, 'number:style');
|
||||
if (sovr = 'false') then begin
|
||||
if (s = 'long') then fmt := fmt + '[ss]' else fmt := fmt + '[s]';
|
||||
end else begin
|
||||
if (s = 'long') then fmt := fmt + 'ss' else fmt := fmt + 's';
|
||||
sovr := '';
|
||||
end;
|
||||
if (sovr = 'false') then
|
||||
fmt := fmt + IfThen(s = 'long', '[ss]', '[s]')
|
||||
else
|
||||
fmt := fmt + IfThen(s = 'long', 'ss', 's');
|
||||
sovr := '';
|
||||
s := GetAttrValue(node, 'number:decimal-places');
|
||||
if (s <> '') and (s <> '0') then
|
||||
fmt := fmt + '.' + DupeString('0', StrToInt(s));
|
||||
@ -1641,8 +1629,14 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
||||
else
|
||||
if nodeName = 'number:text' then begin
|
||||
childnode := node.FirstChild;
|
||||
if childnode <> nil then
|
||||
fmt := fmt + childnode.NodeValue;
|
||||
if childnode <> nil then begin
|
||||
s := childNode.NodeValue;
|
||||
if pos(';', s) > 0 then
|
||||
fmt := fmt + '"' + s + '"'
|
||||
// avoid "misunderstanding" the semicolon as a section separator!
|
||||
else
|
||||
fmt := fmt + childnode.NodeValue;
|
||||
end;
|
||||
end;
|
||||
node := node.NextSibling;
|
||||
end;
|
||||
|
@ -1007,6 +1007,16 @@ end;
|
||||
|
||||
procedure SplitFormatString(const AFormatString: String; out APositivePart,
|
||||
ANegativePart, AZeroPart: String);
|
||||
|
||||
procedure AddToken(AToken: Char; AWhere:Byte);
|
||||
begin
|
||||
case AWhere of
|
||||
0: APositivePart := APositivePart + AToken;
|
||||
1: ANegativePart := ANegativePart + AToken;
|
||||
2: AZeroPart := AZeroPart + AToken;
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
P, PStart, PEnd: PChar;
|
||||
token: Char;
|
||||
@ -1025,24 +1035,28 @@ begin
|
||||
while P < PEnd do begin
|
||||
token := P^;
|
||||
case token of
|
||||
'"': begin // Skip quoted strings
|
||||
'"': begin // Let quoted text intact
|
||||
AddToken(token, where);
|
||||
inc(P);
|
||||
token := P^;
|
||||
while (P < PEnd) and (token <> '"') do begin
|
||||
AddToken(token, where);
|
||||
inc(P);
|
||||
token := P^;
|
||||
end;
|
||||
AddToken(token, where);
|
||||
end;
|
||||
';': begin // Separator between parts
|
||||
inc(where);
|
||||
if where = 3 then
|
||||
exit;
|
||||
end
|
||||
else case where of
|
||||
0: APositivePart := APositivePart + token;
|
||||
1: ANegativePart := ANegativePart + token;
|
||||
2: AZeroPart := AZeroPart + token;
|
||||
end;
|
||||
'\': begin // Skip "Escape" character and add next char immediately
|
||||
inc(P);
|
||||
token := P^;
|
||||
AddToken(token, where);
|
||||
end;
|
||||
else AddToken(token, where);
|
||||
end;
|
||||
inc(P);
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user