You've already forked lazarus-ccr
fpspreadsheet: Add metadata writer for Excel XML. Fix usage of UTC in the Excel metadata.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7580 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -5,7 +5,7 @@ uses
|
|||||||
windows,
|
windows,
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
SysUtils,
|
SysUtils,
|
||||||
fpspreadsheet, fpstypes, xlsxooxml, fpsopendocument;
|
fpspreadsheet, fpstypes, xlsxooxml, fpsopendocument, xlsxml;
|
||||||
|
|
||||||
function GetUserName: String;
|
function GetUserName: String;
|
||||||
// http://forum.lazarus.freepascal.org/index.php/topic,23171.msg138057.html#msg138057
|
// http://forum.lazarus.freepascal.org/index.php/topic,23171.msg138057.html#msg138057
|
||||||
@ -76,7 +76,8 @@ begin
|
|||||||
sheet.WriteText(2, 3, 'abc');
|
sheet.WriteText(2, 3, 'abc');
|
||||||
sheet.WriteBackgroundColor(2, 3, scYellow);
|
sheet.WriteBackgroundColor(2, 3, scYellow);
|
||||||
book.WriteToFile('test.xlsx', true);
|
book.WriteToFile('test.xlsx', true);
|
||||||
book.WritetoFile('test.ods', true);
|
book.WriteToFile('test.ods', true);
|
||||||
|
book.WriteToFile('test.xml', true)
|
||||||
finally
|
finally
|
||||||
book.Free;
|
book.Free;
|
||||||
end;
|
end;
|
||||||
|
@ -41,6 +41,8 @@ const
|
|||||||
ISO8601Format='yyyymmdd"T"hhmmss';
|
ISO8601Format='yyyymmdd"T"hhmmss';
|
||||||
{@@ Extended ISO 8601 date/time format, used in e.g. ODF/opendocument }
|
{@@ Extended ISO 8601 date/time format, used in e.g. ODF/opendocument }
|
||||||
ISO8601FormatExtended='yyyy"-"mm"-"dd"T"hh":"mm":"ss';
|
ISO8601FormatExtended='yyyy"-"mm"-"dd"T"hh":"mm":"ss';
|
||||||
|
{@@ Extended ISO 8601 date/time format, as UTC }
|
||||||
|
ISO8601FormatExtendedUTC='yyyy"-"mm"-"dd"T"hh":"mm":"ss"Z"';
|
||||||
{@@ ISO 8601 date-only format, used in ODF/opendocument }
|
{@@ ISO 8601 date-only format, used in ODF/opendocument }
|
||||||
ISO8601FormatDateOnly='yyyy"-"mm"-"dd';
|
ISO8601FormatDateOnly='yyyy"-"mm"-"dd';
|
||||||
{@@ ISO 8601 time-only format, used in ODF/opendocument }
|
{@@ ISO 8601 time-only format, used in ODF/opendocument }
|
||||||
@ -3147,6 +3149,7 @@ end;
|
|||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Converts an ISO8601-formatted date/time to TDateTime
|
Converts an ISO8601-formatted date/time to TDateTime
|
||||||
|
Assumes UTC when the input string ends with 'Z' and converts to local time.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function ISO8601StrToDateTime(s: String): TDateTime;
|
function ISO8601StrToDateTime(s: String): TDateTime;
|
||||||
// example: 2020-07-28T11:07:36Z
|
// example: 2020-07-28T11:07:36Z
|
||||||
@ -3157,6 +3160,7 @@ var
|
|||||||
hours, mins, days: integer;
|
hours, mins, days: integer;
|
||||||
secs: Double;
|
secs: Double;
|
||||||
hrPos, minPos, secPos: integer;
|
hrPos, minPos, secPos: integer;
|
||||||
|
ms: Double;
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
|
|
||||||
@ -3180,12 +3184,13 @@ begin
|
|||||||
s[p] := ' ';
|
s[p] := ' ';
|
||||||
// Strip milliseconds?
|
// Strip milliseconds?
|
||||||
p := Pos('.', s);
|
p := Pos('.', s);
|
||||||
if (p > 1) then
|
if (p > 1) then begin
|
||||||
s := Copy(s, 1, p-1);
|
ms := StrToFloat('0' + Copy(s, p, MaxInt), fs);
|
||||||
Result := StrToDateTime(s, fs);
|
end else
|
||||||
exit;
|
ms := 0;
|
||||||
end;
|
Result := StrToDateTime(s, fs) + ms;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
p := pos('PT', s);
|
p := pos('PT', s);
|
||||||
if p = 1 then
|
if p = 1 then
|
||||||
begin
|
begin
|
||||||
@ -3213,10 +3218,12 @@ begin
|
|||||||
days := hours div 24;
|
days := hours div 24;
|
||||||
hours := hours mod 24;
|
hours := hours mod 24;
|
||||||
Result := days + (hours + (mins + secs/60) / 60) / 24;
|
Result := days + (hours + (mins + secs/60) / 60) / 24;
|
||||||
|
end else
|
||||||
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if isUTC then
|
if isUTC then
|
||||||
Result := Result + GetLocalTimeOffset / (60*24);
|
Result := Result - GetLocalTimeOffset / MinsPerDay;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -2660,21 +2660,69 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadExcelXMLWriter.WriteDocumentProperties(AStream: TStream);
|
procedure TsSpreadExcelXMLWriter.WriteDocumentProperties(AStream: TStream);
|
||||||
|
const
|
||||||
|
LE = LineEnding;
|
||||||
|
var
|
||||||
|
sTitle: String;
|
||||||
|
sAuthor: String;
|
||||||
|
sLastAuthor: String;
|
||||||
|
sDateCreated: String;
|
||||||
|
sDateLastSaved: String;
|
||||||
|
book: TsWorkbook;
|
||||||
|
dt: TDateTime;
|
||||||
begin
|
begin
|
||||||
AppendToStream(AStream, INDENT1 +
|
book := TsWorkbook(FWorkbook);
|
||||||
'<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office" />' + LineEnding);
|
|
||||||
|
|
||||||
// replace by these when fpspreadsheet supports these meta data.
|
if (book.MetaData.Title = '') and
|
||||||
{
|
(book.MetaData.CreatedBy = '') and (book.MetaData.LastModifiedBy = '') and
|
||||||
AppendToSstream(AStream, INDENT1 +
|
(book.MetaData.DateCreated <= 0) and (book.MetaData.DateLastModified <= 0) then
|
||||||
'<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">' + LineEnding + INDENT2 +
|
begin
|
||||||
'<Author></Author>' + LineEnding + INDENT2 +
|
AppendToStream(AStream, INDENT1 +
|
||||||
'<LastAuthor></LastAuthor>' + LineEnding + INDENT2 +
|
'<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office" />' + LE);
|
||||||
'<Created></Created>' + LineEnding + Indent2 + // Date in format YYYY-mm-ddThh:nn:ssZ
|
exit;
|
||||||
'<Version>16.00</Version>' + LineEnding + Indent1 +
|
end;
|
||||||
'</DocumentProperties>' + LineEnding
|
|
||||||
|
if book.MetaData.Title <> '' then
|
||||||
|
sTitle := '<Title>' + book.MetaData.Title + '</Title>' + LE + INDENT2
|
||||||
|
else
|
||||||
|
sTitle := '';
|
||||||
|
|
||||||
|
if book.MetaData.CreatedBy <> '' then
|
||||||
|
sAuthor := '<Author>' + book.MetaData.CreatedBy + '</Author>' + LE + INDENT2
|
||||||
|
else
|
||||||
|
sAuthor := '';
|
||||||
|
|
||||||
|
if book.MetaData.LastModifiedBy <> '' then
|
||||||
|
sLastAuthor := '<LastAuthor>' + book.MetaData.LastModifiedBy + '</LastAuthor>' + LE + INDENT2
|
||||||
|
else
|
||||||
|
sLastAuthor := '';
|
||||||
|
|
||||||
|
// Dates are UTC and in format YYYY-mm-ddThh:nn:ssZ
|
||||||
|
if book.MetaData.DateCreated > 0 then begin
|
||||||
|
dt := book.MetaData.DateCreated + GetLocalTimeOffset / (24*60);
|
||||||
|
sDateCreated := FormatDateTime(ISO8601FormatExtendedUTC, dt);
|
||||||
|
sDateCreated := '<Created>' + sDateCreated + '</Created>' + LE + INDENT2;
|
||||||
|
end else
|
||||||
|
sDateCreated := '';
|
||||||
|
|
||||||
|
if book.MetaData.DateLastModified > 0 then
|
||||||
|
begin
|
||||||
|
dt := book.MetaData.DateLastModified + GetLocalTimeOffset / (24*60);
|
||||||
|
sDateLastSaved := FormatDateTime(ISO8601FormatExtendedUTC, dt);
|
||||||
|
sDateLastSaved := '<LastSaved>' + sDateLastSaved + '</LastSaved>' + LE + INDENT2;
|
||||||
|
end else
|
||||||
|
sDateLastSaved := '';
|
||||||
|
|
||||||
|
AppendToStream(AStream, INDENT1 +
|
||||||
|
'<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">' + LE + INDENT2 +
|
||||||
|
sTitle +
|
||||||
|
sAuthor +
|
||||||
|
sLastAuthor +
|
||||||
|
sDateCreated +
|
||||||
|
sDateLastSaved +
|
||||||
|
'<Version>16.00</Version>' + LE + Indent1 +
|
||||||
|
'</DocumentProperties>' + LE
|
||||||
);
|
);
|
||||||
}
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadExcelXMLWriter.WriteError(AStream: TStream;
|
procedure TsSpreadExcelXMLWriter.WriteError(AStream: TStream;
|
||||||
|
@ -6101,6 +6101,7 @@ procedure TsSpreadOOXMLWriter.WriteMetaData(AStream: TStream);
|
|||||||
var
|
var
|
||||||
book: TsWorkbook;
|
book: TsWorkbook;
|
||||||
s: String;
|
s: String;
|
||||||
|
dt: TDateTime;
|
||||||
begin
|
begin
|
||||||
book := TsWorkbook(FWorkbook);
|
book := TsWorkbook(FWorkbook);
|
||||||
|
|
||||||
@ -6152,15 +6153,17 @@ begin
|
|||||||
|
|
||||||
if book.MetaData.DateCreated > 0 then
|
if book.MetaData.DateCreated > 0 then
|
||||||
begin
|
begin
|
||||||
s := FormatDateTime(ISO8601FormatExtended, book.MetaData.DateCreated) + 'Z';
|
dt := book.MetaData.DateCreated + GetLocalTimeOffset / MinsPerDay;
|
||||||
|
s := FormatDateTime(ISO8601FormatExtendedUTC, dt);
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<dcterms:created xsi:type="dcterms:W3CDTF">%s</dcterms:created>', [s]));
|
'<dcterms:created xsi:type="dcterms:W3CDTF">%s</dcterms:created>', [s]));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if book.MetaData.DateLastModified <= 0 then
|
if book.MetaData.DateLastModified <= 0 then
|
||||||
s := FormatDateTime(ISO8601FormatExtended, book.MetaData.DateCreated) + 'Z'
|
dt := book.MetaData.DateCreated + GetLocalTimeOffset / MinsPerDay
|
||||||
else
|
else
|
||||||
s := FormatDateTime(ISO8601FormatExtended, book.MetaData.DateLastModified) + 'Z';
|
dt := book.MetaData.DateLastModified + GetLocalTimeOffset / MinsPerDay;
|
||||||
|
s := FormatDateTime(ISO8601FormatExtendedUTC, dt);
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<dcterms:modified xsi:type="dcterms:W3CDTF">%s</dcterms:modified>', [s]));
|
'<dcterms:modified xsi:type="dcterms:W3CDTF">%s</dcterms:modified>', [s]));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user