diff --git a/components/fpspreadsheet/examples/spready/spready.lpi b/components/fpspreadsheet/examples/spready/spready.lpi
index 6094368b7..59f0c33d7 100644
--- a/components/fpspreadsheet/examples/spready/spready.lpi
+++ b/components/fpspreadsheet/examples/spready/spready.lpi
@@ -116,6 +116,7 @@
+
@@ -131,16 +132,20 @@
+
+
+
+
diff --git a/components/fpspreadsheet/fpscsv.pas b/components/fpspreadsheet/fpscsv.pas
index 22b97f371..04990b870 100644
--- a/components/fpspreadsheet/fpscsv.pas
+++ b/components/fpspreadsheet/fpscsv.pas
@@ -12,8 +12,10 @@ type
TsCSVReader = class(TsCustomSpreadReader)
private
FWorksheetName: String;
+ FFormatSettings: TFormatSettings;
function IsBool(AText: String; out AValue: Boolean): Boolean;
- function IsDateTime(AText: String; out ADateTime: TDateTime): Boolean;
+ function IsDateTime(AText: String; out ADateTime: TDateTime;
+ out ANumFormat: TsNumberFormat): Boolean;
function IsNumber(AText: String; out ANumber: Double; out ANumFormat: TsNumberFormat;
out ADecimals: Integer; out ACurrencySymbol, AWarning: String): Boolean;
function IsQuotedText(var AText: String): Boolean;
@@ -34,6 +36,7 @@ type
private
FCSVBuilder: TCSVBuilder;
FEncoding: String;
+ FFormatSettings: TFormatSettings;
protected
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
ACell: PCell); override;
@@ -197,7 +200,8 @@ end;
constructor TsCSVReader.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
- ReplaceFormatSettings(CSVParams.FormatSettings, AWorkbook.FormatSettings);
+ FFormatSettings := CSVParams.FormatSettings;
+ ReplaceFormatSettings(FFormatSettings, AWorkbook.FormatSettings);
FWorksheetName := 'Sheet1'; // will be replaced by filename
end;
@@ -216,9 +220,45 @@ begin
Result := false;
end;
-function TsCSVReader.IsDateTime(AText: String; out ADateTime: TDateTime): Boolean;
+function TsCSVReader.IsDateTime(AText: String; out ADateTime: TDateTime;
+ out ANumFormat: TsNumberFormat): Boolean;
+
+ { Test whether the text is formatted according to a built-in date/time format.
+ Converts the obtained date/time value back to a string and compares. }
+ function TestFormat(lNumFmt: TsNumberFormat): Boolean;
+ var
+ fmt: string;
+ begin
+ fmt := BuildDateTimeFormatString(lNumFmt, FFormatSettings);
+ Result := FormatDateTime(fmt, ADateTime, FFormatSettings) = AText;
+ if Result then ANumFormat := lNumFmt;
+ end;
+
begin
- Result := TryStrToDateTime(AText, ADateTime, CSVParams.FormatSettings);
+ Result := TryStrToDateTime(AText, ADateTime, FFormatSettings);
+ if Result then
+ begin
+ ANumFormat := nfCustom;
+ if abs(ADateTime) > 1 then // this is most probably a date
+ begin
+ if TestFormat(nfShortDateTime) then
+ exit;
+ if TestFormat(nfLongDate) then
+ exit;
+ if TestFormat(nfShortDate) then
+ exit;
+ end else
+ begin // this case is time-only
+ if TestFormat(nfLongTimeAM) then
+ exit;
+ if TestFormat(nfLongTime) then
+ exit;
+ if TestFormat(nfShortTimeAM) then
+ exit;
+ if TestFormat(nfShortTime) then
+ exit;
+ end;
+ end;
end;
function TsCSVReader.IsNumber(AText: String; out ANumber: Double;
@@ -234,9 +274,7 @@ begin
// To detect whether the text is a currency value we look for the currency
// string. If we find it, we delete it and convert the remaining string to
// a number.
- ACurrencySymbol := StrUtils.IfThen(CSVParams.FormatSettings.CurrencyString = '',
- FWorkbook.FormatSettings.CurrencyString,
- CSVParams.FormatSettings.CurrencyString);
+ ACurrencySymbol := FFormatSettings.CurrencyString;
if RemoveCurrencySymbol(ACurrencySymbol, AText) then
begin
if IsNegative(AText) then
@@ -251,15 +289,15 @@ begin
if CSVParams.AutoDetectNumberFormat then
Result := TryStrToFloatAuto(AText, ANumber, DecSep, ThousSep, AWarning)
else begin
- Result := TryStrToFloat(AText, ANumber, CSVParams.FormatSettings);
+ Result := TryStrToFloat(AText, ANumber, FFormatSettings);
if Result then
begin
- if pos(CSVParams.FormatSettings.DecimalSeparator, AText) = 0
+ if pos(FFormatSettings.DecimalSeparator, AText) = 0
then DecSep := #0
- else DecSep := CSVParams.FormatSettings.DecimalSeparator;
+ else DecSep := FFormatSettings.DecimalSeparator;
if pos(CSVParams.FormatSettings.ThousandSeparator, AText) = 0
then ThousSep := #0
- else ThousSep := CSVParams.FormatSettings.ThousandSeparator;
+ else ThousSep := FFormatSettings.ThousandSeparator;
end;
end;
@@ -369,15 +407,8 @@ begin
// Check for a DATE/TIME cell
// No idea how to apply the date/time formatsettings here...
- if IsDateTime(AText, dtValue) then
+ if IsDateTime(AText, dtValue, nf) then
begin
- if dtValue < 1.0 then // this is a time alone
- nf := nfLongTime
- else
- if frac(dtValue) = 0.0 then // this is a date alone
- nf := nfShortDate
- else // this is date + time
- nf := nfShortDateTime;
FWorksheet.WriteDateTime(ARow, ACol, dtValue, nf);
exit;
end;
@@ -473,7 +504,8 @@ end;
constructor TsCSVWriter.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
- ReplaceFormatSettings(CSVParams.FormatSettings, FWorkbook.FormatSettings);
+ FFormatSettings := CSVParams.FormatSettings;
+ ReplaceFormatSettings(FFormatSettings, FWorkbook.FormatSettings);
if CSVParams.Encoding = '' then
FEncoding := 'utf8'
else
@@ -561,9 +593,9 @@ begin
if ACell = nil then
exit;
if CSVParams.NumberFormat <> '' then
- s := Format(CSVParams.NumberFormat, [AValue], CSVParams.FormatSettings)
+ s := Format(CSVParams.NumberFormat, [AValue], FFormatSettings)
else
- s := FWorksheet.ReadAsUTF8Text(ACell, CSVParams.FormatSettings);
+ s := FWorksheet.ReadAsUTF8Text(ACell, FFormatSettings);
s := ConvertEncoding(s, EncodingUTF8, FEncoding);
FCSVBuilder.AppendCell(s);
end;
diff --git a/components/fpspreadsheet/tests/formattests.pas b/components/fpspreadsheet/tests/formattests.pas
index 1485c8639..01fd62fd0 100644
--- a/components/fpspreadsheet/tests/formattests.pas
+++ b/components/fpspreadsheet/tests/formattests.pas
@@ -138,6 +138,7 @@ type
procedure TestWriteRead_OOXML_WordWrap;
{ CSV Tests }
+ procedure TestWriteRead_CSV_DateTimeFormats;
procedure TestWriteRead_CSV_NumberFormats_0;
procedure TestWriteRead_CSV_NumberFormats_1;
end;
@@ -319,6 +320,9 @@ end;
procedure TSpreadWriteReadFormatTests.TestWriteRead_NumberFormats(AFormat: TsSpreadsheetFormat;
AVariant: Integer = 0);
+{ AVariant specifies variants for csv:
+ 0 = decimal and thousand separator as in workbook's FormatSettings,
+ 1 = intercanged }
var
MyWorksheet: TsWorksheet;
MyWorkbook: TsWorkbook;
@@ -476,7 +480,7 @@ begin
MyWorkbook := TsWorkbook.Create;
try
MyWorkbook.ReadFromFile(TempFile, AFormat);
- if AFormat = sfExcel2 then
+ if AFormat in [sfExcel2, sfCSV] then
MyWorksheet := MyWorkbook.GetFirstWorksheet
else
MyWorksheet := GetWorksheetByName(MyWorkbook, FmtDateTimesSheet);
@@ -525,6 +529,12 @@ begin
TestWriteRead_DateTimeFormats(sfOOXML);
end;
+procedure TSpreadWriteReadFormatTests.TestWriteRead_CSV_DateTimeFormats;
+begin
+ TestWriteRead_DateTimeFormats(sfCSV);
+end;
+
+
{ --- Alignment tests --- }
procedure TSpreadWriteReadFormatTests.TestWriteRead_Alignment(AFormat: TsSpreadsheetFormat);