sw/qa/uitest/data/redline-para-join.docx     |binary
 sw/qa/uitest/writer_tests7/tdf90401.py       |  104 +++++++++++++++++++++++++--
 sw/source/filter/ww8/docxattributeoutput.cxx |   79 ++++++++++++++++----
 sw/source/filter/ww8/docxexport.cxx          |    3 
 sw/source/filter/ww8/docxexport.hxx          |    7 +
 xmloff/source/draw/sdxmlexp.cxx              |    8 +-
 xmloff/source/text/XMLRedlineExport.cxx      |   18 ++--
 7 files changed, 185 insertions(+), 34 deletions(-)

New commits:
commit ded2452a52d21131347a0dc2e25c8161f20fcfad
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Fri Jun 18 13:03:17 2021 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Sat Jul 3 12:54:39 2021 +0200

    tdf#142902 DOCX export: remove personal info of comments and changes
    
    If Options → LibreOffice → Security → Security Options
    and Warnings → Options... → Security Options → Remove personal
    information on saving" is enabled.
    
    Use the same time (Unix epoch) for mandatory time stamps, and
    replace authors with "Author1", "Author2", ... and creator-initials
    with "1", "2", "3" etc., also to avoid of joining adjacent redline
    ranges.
    
    Note: to see the work of the unit test in Linux command line:
    
    (cd sw && make UITest_writer_tests7 
UITEST_TEST_NAME="tdf90401.tdf90401.test_tdf142902_remove_personal_info_in_DOCX"
 SAL_USE_VCLPLUGIN=gen)
    
    Follow-up to commit 12da70f88517bf3c053afe1c504bb70bd27573f2
    "tdf#90401 xmloff: remove personal info of comments and changes".
    
    Change-Id: Ice996f171f5d82d13ce0ea2e4833696af0aab90c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117444
    Tested-by: Jenkins
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/sw/qa/uitest/data/redline-para-join.docx 
b/sw/qa/uitest/data/redline-para-join.docx
new file mode 100644
index 000000000000..c1ed90f801fb
Binary files /dev/null and b/sw/qa/uitest/data/redline-para-join.docx differ
diff --git a/sw/qa/uitest/writer_tests7/tdf90401.py 
b/sw/qa/uitest/writer_tests7/tdf90401.py
index c09783638fd3..4850a4cd108f 100644
--- a/sw/qa/uitest/writer_tests7/tdf90401.py
+++ b/sw/qa/uitest/writer_tests7/tdf90401.py
@@ -40,7 +40,11 @@ class tdf90401(UITestCase):
 
                 with 
self.ui_test.execute_blocking_action(xOptions.executeAction, args=('CLICK', 
()), close_button="") as dialog:
                     xRemovePersonal = dialog.getChild('removepersonal')
-                    xRemovePersonal.executeAction('CLICK', tuple())
+                    if get_state_as_dict(xRemovePersonal)['Selected'] == 
"false":
+                        xRemovePersonal.executeAction('CLICK', tuple())
+                    
self.ui_test.wait_until_property_is_updated(xRemovePersonal, "Selected", "true")
+                    
self.assertEqual(get_state_as_dict(xRemovePersonal)["Selected"], "true")
+
                     xOkBtn = dialog.getChild('ok')
                     # FIXME: we can't use close_dialog_through_button here, 
the dialog doesn't emit the
                     # event DialogClosed after closing
@@ -78,13 +82,99 @@ class tdf90401(UITestCase):
                     self.assertEqual(year, 0)
 
                     # check removed personal info on tracked changes
+                    try:
+                        
self.ui_test.execute_modeless_dialog_through_command('.uno:AcceptTrackedChanges')
+                        xTrackDlg = self.xUITest.getTopFocusWindow()
+                        xTreeList = xTrackDlg.getChild('writerchanges')
+                        state = get_state_as_dict(xTreeList)
+                        # This was 'NL\t11/03/2020 19:19:05\t', containing 
personal info
+                        self.assertEqual(state['SelectEntryText'], 
'Author1\t01/01/1970 00:00:00\t')
+                    except:
+                        # skip the test for Clang's exception "Dialog not 
executed for..."
+                        pass
+
+
+   def test_tdf142902_remove_personal_info_in_DOCX(self):
+
+        # load a test document with a tracked change, and add a comment
+
+        with 
self.ui_test.load_file(get_url_for_data_file('redline-para-join.docx')) as 
writer_doc:
+
+            xWriterDoc = self.xUITest.getTopFocusWindow()
+            xWriterEdit = xWriterDoc.getChild('writer_edit')
+
+            selection = self.xUITest.executeCommand('.uno:SelectAll')
+            self.xUITest.executeCommand('.uno:InsertAnnotation')
+
+            # enable remove personal info security option
+
+            with 
self.ui_test.execute_dialog_through_command('.uno:OptionsTreeDialog') as 
xDialog:
+                xPages = xDialog.getChild('pages')
+                xGenEntry = xPages.getChild('0')
+                xSecurityPage = xGenEntry.getChild('6')
+                xSecurityPage.executeAction('SELECT', tuple())
+                # Click Button Options...
+                xOptions = xDialog.getChild('options')
+
+                with 
self.ui_test.execute_blocking_action(xOptions.executeAction, args=('CLICK', 
()), close_button="") as dialog:
+                    xRemovePersonal = dialog.getChild('removepersonal')
+                    if get_state_as_dict(xRemovePersonal)['Selected'] == 
"false":
+                        xRemovePersonal.executeAction('CLICK', tuple())
+                    
self.ui_test.wait_until_property_is_updated(xRemovePersonal, "Selected", "true")
+                    
self.assertEqual(get_state_as_dict(xRemovePersonal)["Selected"], "true")
+
+                    xOkBtn = dialog.getChild('ok')
+                    # FIXME: we can't use close_dialog_through_button here, 
the dialog doesn't emit the
+                    # event DialogClosed after closing
+                    xOkBtn.executeAction('CLICK', tuple())
+
+            # save and reload the document to remove personal info
+
+            with TemporaryDirectory() as tempdir:
+                xFilePath = os.path.join(tempdir, 'redline-para-join-tmp.docx')
+
+                # Save Copy as
+                with 
self.ui_test.execute_dialog_through_command('.uno:SaveAs', close_button="open") 
as xDialog:
+                    xFileName = xDialog.getChild('file_name')
+                    xFileName.executeAction('TYPE', 
mkPropertyValues({'KEYCODE':'CTRL+A'}))
+                    xFileName.executeAction('TYPE', 
mkPropertyValues({'KEYCODE':'BACKSPACE'}))
+                    xFileName.executeAction('TYPE', mkPropertyValues({'TEXT': 
xFilePath}))
+
+                # DOCX confirmation dialog is displayed
+                xWarnDialog = self.xUITest.getTopFocusWindow()
+                xOK = xWarnDialog.getChild("save")
+                self.ui_test.close_dialog_through_button(xOK)
+
+                # Close the Writer document
+                self.ui_test.close_doc()
+
+                with self.ui_test.load_file(systemPathToFileUrl(xFilePath)) as 
writer_doc2:
 
-                    
self.ui_test.execute_modeless_dialog_through_command('.uno:AcceptTrackedChanges')
-                    xTrackDlg = self.xUITest.getTopFocusWindow()
-                    xTreeList = xTrackDlg.getChild('writerchanges')
-                    state = get_state_as_dict(xTreeList)
-                    # This was 'NL\t11/03/2020 19:19:05\t', containing 
personal info
-                    self.assertEqual(state['SelectEntryText'], 
'Author1\t01/01/1970 00:00:00\t')
+                    # check removed personal info on comments
+
+                    textfields = writer_doc2.getTextFields()
+                    author = ""
+                    year = -1
+                    for textfield in textfields:
+                        if 
textfield.supportsService("com.sun.star.text.TextField.Annotation"):
+                            author = textfield.Author
+                            year = textfield.Date.Year
+                    # This was 'Unknown Author'
+                    self.assertEqual(author, 'Author2')
+                    # This was 2021
+                    self.assertEqual(year, 0)
+
+                    # check removed personal info on tracked changes
 
+                    try:
+                        
self.ui_test.execute_modeless_dialog_through_command('.uno:AcceptTrackedChanges')
+                        xTrackDlg = self.xUITest.getTopFocusWindow()
+                        xTreeList = xTrackDlg.getChild('writerchanges')
+                        state = get_state_as_dict(xTreeList)
+                        # This was 'NL\t11/03/2020 19:19:05\t', containing 
personal info
+                        self.assertEqual(state['SelectEntryText'], 
'Author1\t01/01/1970 00:00:00\t')
+                    except:
+                        # skip the test for Clang's exception "Dialog not 
executed for..."
+                        pass
 
 # vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 19dc42aa119c..bbf4994a1d05 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -100,6 +100,8 @@
 #include <svx/unobrushitemhelper.hxx>
 #include <svl/grabbagitem.hxx>
 #include <sfx2/sfxbasemodel.hxx>
+#include <tools/date.hxx>
+#include <tools/datetime.hxx>
 #include <tools/datetimeutils.hxx>
 #include <tools/UnitConversion.hxx>
 #include <svl/whiter.hxx>
@@ -3145,9 +3147,15 @@ void DocxAttributeOutput::Redline( const SwRedlineData* 
pRedlineData)
     if ( !pRedlineData )
         return;
 
+    SvtSecurityOptions aSecOpt;
+    bool bRemovePersonalInfo = aSecOpt.IsOptionSet(
+        SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo );
+
     OString aId( OString::number( pRedlineData->GetSeqNo() ) );
     const OUString &rAuthor( SW_MOD()->GetRedlineAuthor( 
pRedlineData->GetAuthor() ) );
-    OString aDate( DateTimeToOString( pRedlineData->GetTimeStamp() ) );
+    OString aDate( DateTimeToOString( bRemovePersonalInfo
+            ? DateTime(Date( 1, 1, 1970 )) // Epoch time
+            : pRedlineData->GetTimeStamp() ) );
 
     switch( pRedlineData->GetType() )
     {
@@ -3160,7 +3168,9 @@ void DocxAttributeOutput::Redline( const SwRedlineData* 
pRedlineData)
     case RedlineType::Format:
         m_pSerializer->startElementNS( XML_w, XML_rPrChange,
                 FSNS( XML_w, XML_id ), aId,
-                FSNS( XML_w, XML_author ), rAuthor,
+                FSNS( XML_w, XML_author ), bRemovePersonalInfo
+                    ? "Author" + OUString::number( 
GetExport().GetInfoID(rAuthor) )
+                    : rAuthor,
                 FSNS( XML_w, XML_date ), aDate );
 
         m_pSerializer->endElementNS( XML_w, XML_rPrChange );
@@ -3169,7 +3179,9 @@ void DocxAttributeOutput::Redline( const SwRedlineData* 
pRedlineData)
     case RedlineType::ParagraphFormat:
         m_pSerializer->startElementNS( XML_w, XML_pPrChange,
                 FSNS( XML_w, XML_id ), aId,
-                FSNS( XML_w, XML_author ), rAuthor,
+                FSNS( XML_w, XML_author ), bRemovePersonalInfo
+                    ? "Author" + OUString::number( 
GetExport().GetInfoID(rAuthor) )
+                    : rAuthor,
                 FSNS( XML_w, XML_date ), aDate );
 
         // Check if there is any extra data stored in the redline object
@@ -3243,10 +3255,18 @@ void DocxAttributeOutput::StartRedline( const 
SwRedlineData * pRedlineData )
 
     OString aId( OString::number( m_nRedlineId++ ) );
 
+    SvtSecurityOptions aSecOpt;
+    bool bRemovePersonalInfo = aSecOpt.IsOptionSet(
+        SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo );
+
     const OUString &rAuthor( SW_MOD()->GetRedlineAuthor( 
pRedlineData->GetAuthor() ) );
-    OString aAuthor( OUStringToOString( rAuthor, RTL_TEXTENCODING_UTF8 ) );
+    OString aAuthor( OUStringToOString( bRemovePersonalInfo
+                        ? "Author" + OUString::number( 
GetExport().GetInfoID(rAuthor) )
+                        : rAuthor, RTL_TEXTENCODING_UTF8 ) );
 
-    OString aDate( DateTimeToOString( pRedlineData->GetTimeStamp() ) );
+    OString aDate( DateTimeToOString( bRemovePersonalInfo
+            ? DateTime(Date( 1, 1, 1970 )) // Epoch time
+            : pRedlineData->GetTimeStamp() ) );
 
     switch ( pRedlineData->GetType() )
     {
@@ -4357,6 +4377,11 @@ void DocxAttributeOutput::TableRowRedline( 
ww8::WW8TableNodeInfoInner::Pointer_t
     const SwRedlineTable& aRedlineTable = 
m_rExport.m_rDoc.getIDocumentRedlineAccess().GetRedlineTable();
     const SvxPrintItem *pHasTextChangesOnlyProp =
             
pTabLine->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
+
+    SvtSecurityOptions aSecOpt;
+    bool bRemovePersonalInfo = aSecOpt.IsOptionSet(
+        SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo );
+
     if ( !aRedlineTable.empty() && pHasTextChangesOnlyProp && 
!pHasTextChangesOnlyProp->GetValue() )
     {
         // Tracked row deletion is associated to the newest redline range in 
the row.
@@ -4397,9 +4422,13 @@ void DocxAttributeOutput::TableRowRedline( 
ww8::WW8TableNodeInfoInner::Pointer_t
             // (different IDs for different ranges, also row changes) is also 
portable.
             OString aId( OString::number( m_nRedlineId++ ) );
             const OUString &rAuthor( SW_MOD()->GetRedlineAuthor( 
aRedlineData.GetAuthor() ) );
-            OString aAuthor( OUStringToOString( rAuthor, RTL_TEXTENCODING_UTF8 
) );
+            OString aAuthor( OUStringToOString( bRemovePersonalInfo
+                        ? "Author" + OUString::number( 
GetExport().GetInfoID(rAuthor) )
+                        : rAuthor, RTL_TEXTENCODING_UTF8 ) );
 
-            OString aDate( DateTimeToOString( aRedlineData.GetTimeStamp() ) );
+            OString aDate( DateTimeToOString( bRemovePersonalInfo
+                    ? DateTime(Date( 1, 1, 1970 )) // Epoch time
+                    : aRedlineData.GetTimeStamp() ) );
 
             m_pSerializer->singleElementNS( XML_w, XML_del,
                             FSNS( XML_w, XML_id ), aId,
@@ -4427,9 +4456,13 @@ void DocxAttributeOutput::TableRowRedline( 
ww8::WW8TableNodeInfoInner::Pointer_t
                 {
                     OString aId( OString::number( m_nRedlineId++ ) );
                     const OUString &rAuthor( SW_MOD()->GetRedlineAuthor( 
aRedlineData.GetAuthor() ) );
-                    OString aAuthor( OUStringToOString( rAuthor, 
RTL_TEXTENCODING_UTF8 ) );
+                    OString aAuthor( OUStringToOString( bRemovePersonalInfo
+                        ? "Author" + OUString::number( 
GetExport().GetInfoID(rAuthor) )
+                        : rAuthor, RTL_TEXTENCODING_UTF8 ) );
 
-                    OString aDate( DateTimeToOString( 
aRedlineData.GetTimeStamp() ) );
+                    OString aDate( DateTimeToOString( bRemovePersonalInfo
+                            ? DateTime(Date( 1, 1, 1970 )) // Epoch time
+                            : aRedlineData.GetTimeStamp() ) );
 
                     if (nRedlineType == RedlineType::TableRowInsert)
                         m_pSerializer->singleElementNS( XML_w, XML_ins,
@@ -4453,6 +4486,10 @@ void DocxAttributeOutput::TableCellRedline( 
ww8::WW8TableNodeInfoInner::Pointer_
 {
     const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
 
+    SvtSecurityOptions aSecOpt;
+    bool bRemovePersonalInfo = aSecOpt.IsOptionSet(
+        SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo );
+
     // search next Redline
     const SwExtraRedlineTable& aExtraRedlineTable = 
m_rExport.m_rDoc.getIDocumentRedlineAccess().GetExtraRedlineTable();
     for(sal_uInt16 nCurRedlinePos = 0; nCurRedlinePos < 
aExtraRedlineTable.GetSize(); ++nCurRedlinePos )
@@ -4471,9 +4508,13 @@ void DocxAttributeOutput::TableCellRedline( 
ww8::WW8TableNodeInfoInner::Pointer_
                 {
                     OString aId( OString::number( m_nRedlineId++ ) );
                     const OUString &rAuthor( SW_MOD()->GetRedlineAuthor( 
aRedlineData.GetAuthor() ) );
-                    OString aAuthor( OUStringToOString( rAuthor, 
RTL_TEXTENCODING_UTF8 ) );
+                    OString aAuthor( OUStringToOString( bRemovePersonalInfo
+                        ? "Author" + OUString::number( 
GetExport().GetInfoID(rAuthor) )
+                        : rAuthor, RTL_TEXTENCODING_UTF8 ) );
 
-                    OString aDate( DateTimeToOString( 
aRedlineData.GetTimeStamp() ) );
+                    OString aDate( DateTimeToOString( bRemovePersonalInfo
+                            ? DateTime(Date( 1, 1, 1970 )) // Epoch time
+                            : aRedlineData.GetTimeStamp() ) );
 
                     if (nRedlineType == RedlineType::TableCellInsert)
                         m_pSerializer->singleElementNS( XML_w, XML_cellIns,
@@ -8137,14 +8178,24 @@ void DocxAttributeOutput::WritePostitFieldReference()
 
 DocxAttributeOutput::hasResolved DocxAttributeOutput::WritePostitFields()
 {
+    SvtSecurityOptions aSecOpt;
+    bool bRemovePersonalInfo = aSecOpt.IsOptionSet(
+        SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo );
+
     hasResolved eResult = hasResolved::no;
     for (auto& [f, data] : m_postitFields)
     {
         OString idstr = OString::number(data.id);
         m_pSerializer->startElementNS( XML_w, XML_comment, FSNS( XML_w, XML_id 
), idstr,
-            FSNS( XML_w, XML_author ), f->GetPar1(),
-            FSNS( XML_w, XML_date ), DateTimeToOString(f->GetDateTime()),
-            FSNS( XML_w, XML_initials ), f->GetInitials() );
+            FSNS( XML_w, XML_author ), bRemovePersonalInfo
+                     ? "Author" + OUString::number( 
GetExport().GetInfoID(f->GetPar1()) )
+                     : f->GetPar1(),
+            FSNS( XML_w, XML_date ), DateTimeToOString( bRemovePersonalInfo
+                     ? util::DateTime() // "no date" time
+                     : f->GetDateTime() ),
+            FSNS( XML_w, XML_initials ), bRemovePersonalInfo
+                     ? OUString::number( 
GetExport().GetInfoID(f->GetInitials()) )
+                     : f->GetInitials() );
 
         const bool bNeedParaId = f->GetResolved();
         if (bNeedParaId)
diff --git a/sw/source/filter/ww8/docxexport.cxx 
b/sw/source/filter/ww8/docxexport.cxx
index 0590fea71d35..3eefc919eed8 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -1798,7 +1798,8 @@ DocxExport::DocxExport(DocxExportFilter& rFilter, SwDoc& 
rDocument,
       m_nActiveXControls( 0 ),
       m_nHeadersFootersInSection(0),
       m_bDocm(bDocm),
-      m_bTemplate(bTemplate)
+      m_bTemplate(bTemplate),
+      m_pAuthorIDs(new SvtSecurityMapPersonalInfo)
 {
     // Write the document properties
     WriteProperties( );
diff --git a/sw/source/filter/ww8/docxexport.hxx 
b/sw/source/filter/ww8/docxexport.hxx
index bc96ba187100..4bbd2ea9cb0c 100644
--- a/sw/source/filter/ww8/docxexport.hxx
+++ b/sw/source/filter/ww8/docxexport.hxx
@@ -28,6 +28,7 @@
 
 #include <memory>
 #include <ndole.hxx>
+#include <unotools/securityoptions.hxx>
 
 class DocxAttributeOutput;
 class DocxExportFilter;
@@ -114,6 +115,9 @@ class DocxExport : public MSWordExportBase
     /// Pointer to the Frame of a floating table it is nested in
     const ww8::Frame *m_pFloatingTableFrame = nullptr;
 
+    /// Map authors to remove personal info
+    std::unique_ptr<SvtSecurityMapPersonalInfo> m_pAuthorIDs;
+
 public:
 
     DocxExportFilter& GetFilter() { return m_rFilter; };
@@ -296,6 +300,9 @@ public:
 
     void SetFloatingTableFrame(const ww8::Frame* pF) { m_pFloatingTableFrame = 
pF; }
 
+    // Get author id to remove personal info
+    size_t GetInfoID( const OUString sPersonalInfo ) const { return 
m_pAuthorIDs->GetInfoID(sPersonalInfo); }
+
 private:
     DocxExport( const DocxExport& ) = delete;
 
diff --git a/xmloff/source/draw/sdxmlexp.cxx b/xmloff/source/draw/sdxmlexp.cxx
index db1542fc511f..cdc6a70e31dd 100644
--- a/xmloff/source/draw/sdxmlexp.cxx
+++ b/xmloff/source/draw/sdxmlexp.cxx
@@ -2580,12 +2580,12 @@ void SdXMLExport::exportAnnotations( const 
Reference<XDrawPage>& xDrawPage )
 
                 {
                     // date time
-                    css::util::DateTime aDate( xAnnotation->getDateTime() );
+                    css::util::DateTime aDate( bRemovePersonalInfo
+                            ? css::util::DateTime(0, 0, 0, 0, 1, 1, 1970, 
true) // Epoch time
+                            : xAnnotation->getDateTime() );
                     ::sax::Converter::convertDateTime(sStringBuffer, aDate, 
nullptr, true);
                     SvXMLElementExport aDateElem( *this, XML_NAMESPACE_DC, 
XML_DATE, true, false );
-                    Characters( bRemovePersonalInfo
-                            ? "1970-01-01T00:00::00"
-                            : sStringBuffer.makeStringAndClear() );
+                    Characters( sStringBuffer.makeStringAndClear() );
                 }
 
                 css::uno::Reference < css::text::XText > xText( 
xAnnotation->getTextRange() );
diff --git a/xmloff/source/text/XMLRedlineExport.cxx 
b/xmloff/source/text/XMLRedlineExport.cxx
index fad527a77b59..aa457bf2ad98 100644
--- a/xmloff/source/text/XMLRedlineExport.cxx
+++ b/xmloff/source/text/XMLRedlineExport.cxx
@@ -43,6 +43,8 @@
 #include <xmloff/xmlexp.hxx>
 #include <xmloff/xmluconv.hxx>
 #include <unotools/securityoptions.hxx>
+#include <tools/date.hxx>
+#include <tools/datetime.hxx>
 
 
 using namespace ::com::sun::star;
@@ -459,13 +461,13 @@ void XMLRedlineExport::ExportChangeInfo(
     aAny >>= aDateTime;
     {
         OUStringBuffer sBuf;
-        ::sax::Converter::convertDateTime(sBuf, aDateTime, nullptr);
+        ::sax::Converter::convertDateTime(sBuf, bRemovePersonalInfo
+                ? util::DateTime(0, 0, 0, 0, 1, 1, 1970, true) // Epoch time
+                : aDateTime, nullptr);
         SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC,
                                           XML_DATE, true,
                                           false );
-        rExport.Characters(bRemovePersonalInfo
-                ? "1970-01-01T00:00:00"
-                :  sBuf.makeStringAndClear());
+        rExport.Characters(sBuf.makeStringAndClear());
     }
 
     // comment as <text:p> sequence
@@ -504,10 +506,10 @@ void XMLRedlineExport::ExportChangeInfo(
             util::DateTime aDateTime;
             rVal.Value >>= aDateTime;
             OUStringBuffer sBuf;
-            ::sax::Converter::convertDateTime(sBuf, aDateTime, nullptr);
-            rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_DATE_TIME, 
bRemovePersonalInfo
-                    ? "1970-01-01T00:00:00"
-                    : sBuf.makeStringAndClear());
+            ::sax::Converter::convertDateTime(sBuf, bRemovePersonalInfo
+                    ? util::DateTime(0, 0, 0, 0, 1, 1, 1970, true) // Epoch 
time
+                    : aDateTime, nullptr);
+            rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_DATE_TIME, 
sBuf.makeStringAndClear());
         }
         else if( rVal.Name == "RedlineType" )
         {
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to