Spire.PDF is a professional PDF library applied to creating, writing, editing, handling and reading PDF files without any external dependencies. Get free and professional technical support for Spire.PDF for .NET, Java, Android, C++, Python.

Sat Dec 10, 2022 6:53 pm

Hi :)

Recently I have discovered an issue with PdfDocumentInformation#getCreationDate() method. Consider situation where you have some PDF file that has been created at 2022-12-10 18:07:43 UTC+1 [Europe/Warsaw] (which is 2022-12-10 17:07:43 UTC) and you want to read its creation date using PdfDocumentInformation#getCreationDate():

* If your local time zone (or rather your local time zone offset) is very same as one used during file creation (Europe/Warsaw in this example), then method getCreationDate() returns correct value (which is 2022-12-10 17:07:43)
* If your local time zone has different offset then getCreationDate() returns incorrect values

Take a look on example code with three unit tests which documents the issue: github.com/kr5ture/spire-pdf-default-timezone-example/blob/master/src/test/java/com/example/ExampleTest.java
Code: Select all
package com.example;

import com.spire.pdf.PdfDocument;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.time.Instant;
import java.util.TimeZone;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class ExampleTest {
    @Test
    void when_file_created_at_17_07_UTC_then_should_return_same_when_default_timezone_offset_has_plus_8() throws IOException {
        // given
        TimeZone.setDefault(TimeZone.getTimeZone("Australia/Perth")); // UTC+8
        // and - file created at 2022-12-10 18:07:43 UTC+1 [Europe/Warsaw] which is 2022-12-10 17:07:43 UTC
        Path filePath = Path.of(getClass().getResource("/example.pdf").getPath());
        // and
        PdfDocument pdfDocument = new PdfDocument(Files.newInputStream(filePath, StandardOpenOption.READ));

        // when
        Instant result = pdfDocument.getDocumentInformation()
            .getCreationDate()
            .toInstant(); // <-- should be 2022-12-10 17:07:43 UTC+0

        // then - fails:
        // Expected :2022-12-10T17:07:43Z
        // Actual   :2022-12-10T10:07:43Z
        assertEquals("2022-12-10T17:07:43Z", result.toString());
    }

    @Test
    void when_file_created_at_17_07_UTC_then_should_return_same_when_default_timezone_is_UTC() throws IOException {
        // given
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        // and - file created at 2022-12-10 18:07:43 UTC+1 [Europe/Warsaw] which is 2022-12-10 17:07:43 UTC
        Path filePath = Path.of(getClass().getResource("/example.pdf").getPath());
        // and
        PdfDocument pdfDocument = new PdfDocument(Files.newInputStream(filePath, StandardOpenOption.READ));

        // when
        Instant result = pdfDocument.getDocumentInformation()
            .getCreationDate()
            .toInstant(); // <-- should be 2022-12-10 17:07:43 UTC+0

        // then - fails:
        // Expected :2022-12-10T17:07:43Z
        // Actual   :2022-12-10T18:07:43Z
        assertEquals("2022-12-10T17:07:43Z", result.toString());
    }

    @Test
    void when_file_created_at_17_07_UTC_then_should_return_same_when_default_timezone_is_same_as_one_from_file_creation() throws IOException {
        // given
        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Warsaw")); // UTC+1 at 2022-12-10 (winter time)
        // and - file created at 2022-12-10 18:07:43 UTC+1 [Europe/Warsaw] which is 2022-12-10 17:07:43 UTC
        Path filePath = Path.of(getClass().getResource("/example.pdf").getPath());
        // and
        PdfDocument pdfDocument = new PdfDocument(Files.newInputStream(filePath, StandardOpenOption.READ));

        // when
        Instant result = pdfDocument.getDocumentInformation()
            .getCreationDate()
            .toInstant(); // <-- should be 2022-12-10 17:07:43 UTC+0

        // then - passed!
        assertEquals("2022-12-10T17:07:43Z", result.toString());
    }
}


* when_file_created_at_17_07_UTC_then_should_return_same_when_default_timezone_is_same_as_one_from_file_creation - this test passess
* when_file_created_at_17_07_UTC_then_should_return_same_when_default_timezone_offset_has_plus_8 - this test fails
* when_file_created_at_17_07_UTC_then_should_return_same_when_default_timezone_is_UTC - this test fails

I have tried two sprife.pdf versions (8.10.1 and 8.11.8) and both seems affected.

In addition it seems that creation date attribute contains offset - take a look on pdfinfo output:
Code: Select all
$ pdfinfo -isodates app/src/test/resources/example.pdf
Creator:         Writer
Producer:        LibreOffice 7.4
CreationDate:    2022-12-10T18:07:43+01 // <------ here
Custom Metadata: no
Metadata Stream: no
Tagged:          no
UserProperties:  no
Suspects:        no
Form:            none
JavaScript:      no
Pages:           1
Encrypted:       no
Page size:       595.304 x 841.89 pts (A4)
Page rot:        0
File size:       7484 bytes
Optimized:       no
PDF version:     1.6

kr5tureee
 
Posts: 6
Joined: Sat Dec 10, 2022 6:18 pm

Mon Dec 12, 2022 3:53 am

Hello,

Thanks for your inquiry.
According to the message you provided, I simulated a PDF file to test, and I did notice the issue you mentioned. However, the scenario is normal phenomenon, due to if you change the zone of your computer, the create time also will change when you open the PDF file with Adobe to see the create time.

Sincerely
Abel
E-iceblue support team
User avatar

Abel.He
 
Posts: 1010
Joined: Tue Mar 08, 2022 2:02 am

Sun Jan 08, 2023 9:37 am

Thank you for your reply @Abel.He.
Abel.He wrote:However, the scenario is normal phenomenon, due to if you change the zone of your computer, the create time also will change when you open the PDF file with Adobe to see the create time.

Yes, file creation time will be shown different on two computers working in different timezones because file browsers will adjust it according to operating system local time. Creation time is stored along with current timezone offset (2022-12-10T18:07:43+01) and thats why file browser can make such adjustment. However getCreationDate method seems to retrieve it incorrectly and it seems producing invalid results.

It is hard to debug decompiled com.spire.ms.System.DateTime class but it looks like there is some issue within com.spire.ms.System.DateTime#toJava() method. It uses com.spire.ms.System.DateTime#toJavaTicks() which apparently returns invalid number of miliseconds.

Consider following listing of decompiled com.spire.ms.System.DateTime#toJava() method how it works for:
  • * file created at 2022-12-10 18:07:43 UTC+1 [Europe/Warsaw] (2022-12-10 17:07:43 UTC):
  • * getCreationDate run within UTC timezone (if you try different zone with higher offset difference, then time mismatch after conversion to UTC will be even bigger)

Code: Select all
public class PdfDocumentInformation implements IPdfWrapper {

    // (...)
   
    public Date getCreationDate() {
        return DateTime.toJava(this.spr┾╽());
    }

    // (...)
}


Code: Select all
public static Date toJava(DateTime arg0) { // args=12/10/2022 6:07:43 PM - 6PM was creation time on local time (UTC+1), but for UTC it was 5PM!
    if (arg0 == null) {
        return null;
    } else {
        long var1;
        if (MinValue.equals(arg0)) {
            var1 = MinValueToUnixTicks;
        } else {
            long var3 = arg0.toJavaTicks(); // var3=1670695663000
            var1 = var3 - (long)TimeZone.getDefault().getOffset(var3); // var1=0 - file created in UTC+1, so this should be 1, not 0
        }

        return new Date(var1); // var1 should be timestamp in universal time, not local one
    }
}

kr5tureee
 
Posts: 6
Joined: Sat Dec 10, 2022 6:18 pm

Sun Jan 08, 2023 12:39 pm

Another PoC:

* Create pdf file using LibreOffice Writer (export as PDF)
* Run following snippet:
Code: Select all
System.out.println("1) Case: current timezone is: " + TimeZone.getDefault().getID());

Path filePath = Path.of("/path/to/file/test.pdf");
PdfDocument pdfDocument = new PdfDocument(Files.newInputStream(filePath, StandardOpenOption.READ));

// Using default timezone, same as file creation
Instant o1 = Files.readAttributes(filePath, BasicFileAttributes.class)
    .creationTime()
    .toInstant();
System.out.println("Creation date time based on file attributes: " + o1);

Instant o2 = pdfDocument.getDocumentInformation().getCreationDate().toInstant();
System.out.println("Creation date time based on PdfDocument: " + o2);

// Simulate that code is run in different timezone
TimeZone.setDefault(TimeZone.getTimeZone("Australia/Perth"));
System.out.println("\n2) Case: current timezone is different than creation file: " + TimeZone.getDefault().getID());

Instant o3 = Files.readAttributes(filePath, BasicFileAttributes.class)
    .creationTime()
    .toInstant();
System.out.println("Creation date time based on file attributes: " + o3);

Instant o4 = pdfDocument.getDocumentInformation().getCreationDate().toInstant();
System.out.println("Creation date time based on PdfDocument: " + o4);

Output is following:
Code: Select all
1) Case: current timezone is: Europe/Warsaw
Creation date time based on file attributes: 2023-01-08T12:27:03.830596667Z
Creation date time based on PdfDocument: 2023-01-08T12:27:03Z

2) Case: current timezone is different than creation file: Australia/Perth
Creation date time based on file attributes: 2023-01-08T12:27:03.830596667Z
Creation date time based on PdfDocument: 2023-01-08T05:27:03Z

In my understanding, creation date time should be the same despite local timezone (all instants are presented in UTC, so they should be the same). If you look at the 2nd case, value produced by getCreationDate() seems to be invalid.

kr5tureee
 
Posts: 6
Joined: Sat Dec 10, 2022 6:18 pm

Mon Jan 09, 2023 9:51 am

Hello,

Thanks for your feedback.
Please kindly note that the “getCreationDate()” method returns the UTC time and the “date. toInstant()” method converts the time in another time zone to UTC. If you set the time zone in code, when using the “getCreationDate().toInstant()" method, the time obtained by "getCreationDate()" is treated as the time in the time zone you set instead of the UTC time. Therefore, the result of “getCreationDate().toInstant()” is offset the correct UTC time.

Sincerely
Abel
E-iceblue support team
User avatar

Abel.He
 
Posts: 1010
Joined: Tue Mar 08, 2022 2:02 am

Mon Dec 25, 2023 11:16 am

Hi. Sorry for abandoning this topic a little...

I have recently tried the newest version of the spire.pdf (9.12.0) and in my opinion this still does not work correctly.

Please kindly note that the “getCreationDate()” method returns the UTC time and the “date. toInstant()” method converts the time in another time zone to UTC. If you set the time zone in code, when using the “getCreationDate().toInstant()" method, the time obtained by "getCreationDate()" is treated as the time in the time zone you set instead of the UTC time. Therefore, the result of “getCreationDate().toInstant()” is offset the correct UTC time.

You are right but still getCreationDate() works incorrectly. It treats stored CreationDate metadata as it is UTC and doesn't care about the time offset (it is also stored within CreationDate metadata of PDF file) thus it is impossible to read that date correctly when working with files created in different timezones than one your running your app. Take a look on this file: https://github.com/kr5ture/spire-pdf-de ... xample.pdf

I have printed stats of this file using linux tool pdfinfo.
Code: Select all
$ pdfinfo -rawdates example.pdf

Creator:         Writer
Producer:        LibreOffice 7.4
CreationDate:    D:20221210180743+01'00'


This tool clearly states that time offset is stored within CreationDate metadata and it is 2022-12-10 18:07:43 (+1:00). Now, if you try to read this date using getCreationDate():
Code: Select all
System.out.println(TimeZone.getDefault().toZoneId()); // Prints: Australia/Perth, it's UTC+8

Date result = pdfDocument.getDocumentInformation()
    .getCreationDate();

System.out.println(result); // Prints: Sat Dec 10 18:07:43 AWST 2022


Printed value is incorrect - the actual value is Sat Dec 10 18:07:43 AWST 2022 but it should be Sun Dec 11 01:07:43 AWST 2022.

Check another file https://github.com/PacktPublishing/Mast ... pdated.pdf. Results from pdfinfo
Code: Select all
$ pdfinfo -rawdates "OpenCV Python Course_Updated.pdf"

Producer:        Acrobat Distiller 11.0 (Windows)
CreationDate:    D:20190417171700-04'00'


pdfinfo states that file were created on 2019-04-17 17:17:17 (-4:00), but following code prints incorrect values:

Code: Select all
System.out.println(TimeZone.getDefault().toZoneId()); // Prints: Australia/Perth

Date result = pdfDocument.getDocumentInformation()
    .getCreationDate();

System.out.println(result); // Prints: Wed Apr 17 17:17:00 AWST 2019


Printed Date is Wed Apr 17 17:17:00 AWST 2019 but it should be Tue Apr 18 05:17:17 AWST 2019

Could you take a look?

kr5tureee
 
Posts: 6
Joined: Sat Dec 10, 2022 6:18 pm

Tue Dec 26, 2023 3:59 am

Hello kr5tureee,

Thank you for your feedback.
Based on the information you provided, we conducted a thorough investigation and consulted with our development team. We have confirmed that the "getCreationDate()" method does not calculate the time offset based on the time zone when retrieving the document creation time.
We understand the importance of this functionality and have taken your concern seriously. To address this issue, we have internally logged it as a bug report with the reference number SPIREPDF-6465. Our development team will prioritize this issue and work towards providing a resolution in a future update.
We apologize for any inconvenience this may have caused and thank you for bringing it to our attention. If you have any further questions or require additional assistance, please don't hesitate to reach out to us. We are committed to ensuring the quality and reliability of our products.

Sincerely,
Annika
E-iceblue support team
User avatar

Annika.Zhou
 
Posts: 1657
Joined: Wed Apr 07, 2021 2:50 am

Tue Dec 26, 2023 12:31 pm

Thank you very much @Annika.Zhou !

kr5tureee
 
Posts: 6
Joined: Sat Dec 10, 2022 6:18 pm

Wed Dec 27, 2023 5:38 am

Hello,

You're welcome!
Rest assured that once this issue is resolved, we will notify you immediately.
If you have any further questions or concerns, please don't hesitate to reach out to us.
Thank you for your understanding and support. Have a great day!

Sincerely,
Annika
E-iceblue support team
User avatar

Annika.Zhou
 
Posts: 1657
Joined: Wed Apr 07, 2021 2:50 am

Sun Feb 04, 2024 9:41 am

Hello,

Thanks for your patience!
Glad to inform you that we just released Spire.PDF for Java Version:10.2.0 which fixes the issue of SPIREPDF-6465.
Please download this version and test it.

Sincerely,
Annika
E-iceblue support team
User avatar

Annika.Zhou
 
Posts: 1657
Joined: Wed Apr 07, 2021 2:50 am

Sun Mar 24, 2024 11:03 am

It works like a charm! Thank you very much!

kr5tureee
 
Posts: 6
Joined: Sat Dec 10, 2022 6:18 pm

Mon Mar 25, 2024 6:28 am

Hello,

You're welcome.
If you encounter other issues related to our products in the future, please feel free to contact us.
Have a nice day.

Sincerely,
Annika
E-iceblue support team
User avatar

Annika.Zhou
 
Posts: 1657
Joined: Wed Apr 07, 2021 2:50 am

Return to Spire.PDF

cron