Commit 04fc7c4bea9b4efa38a7398b6db56a8fe5273bfb

Authored by Jay Berkenbilt
1 parent 6a7c4583

Add conversions to ISO-8601 date format

ChangeLog
  1 +2022-05-30 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add QUtil::qpdf_time_to_iso8601 and QUtil::pdf_time_to_iso8601
  4 + for converting PDF/qpdf timestamps to ISO-8601 date format.
  5 +
1 2022-05-18 Jay Berkenbilt <ejb@ql.org> 6 2022-05-18 Jay Berkenbilt <ejb@ql.org>
2 7
3 * Add QUtil::FileCloser to the public API. This is a simple inline 8 * Add QUtil::FileCloser to the public API. This is a simple inline
include/qpdf/QUtil.hh
@@ -284,6 +284,10 @@ namespace QUtil @@ -284,6 +284,10 @@ namespace QUtil
284 QPDF_DLL 284 QPDF_DLL
285 std::string qpdf_time_to_pdf_time(QPDFTime const&); 285 std::string qpdf_time_to_pdf_time(QPDFTime const&);
286 286
  287 + // Convert QPDFTime to a second-granularity ISO-8601 timestamp.
  288 + QPDF_DLL
  289 + std::string qpdf_time_to_iso8601(QPDFTime const&);
  290 +
287 // Convert a PDF timestamp string to a QPDFTime. If syntactically 291 // Convert a PDF timestamp string to a QPDFTime. If syntactically
288 // valid, return true and fill in qtm. If not valid, return false, 292 // valid, return true and fill in qtm. If not valid, return false,
289 // and do not modify qtm. If qtm is null, just check the validity 293 // and do not modify qtm. If qtm is null, just check the validity
@@ -291,6 +295,11 @@ namespace QUtil @@ -291,6 +295,11 @@ namespace QUtil
291 QPDF_DLL 295 QPDF_DLL
292 bool pdf_time_to_qpdf_time(std::string const&, QPDFTime* qtm = nullptr); 296 bool pdf_time_to_qpdf_time(std::string const&, QPDFTime* qtm = nullptr);
293 297
  298 + // Convert PDF timestamp to a second-granularity ISO-8601
  299 + // timestamp. If syntactically valid, return true and initialize
  300 + // iso8601. Otherwise, return false.
  301 + bool pdf_time_to_iso8601(std::string const& pdf_time, std::string& iso8601);
  302 +
294 // Return a string containing the byte representation of the UTF-8 303 // Return a string containing the byte representation of the UTF-8
295 // encoding for the unicode value passed in. 304 // encoding for the unicode value passed in.
296 QPDF_DLL 305 QPDF_DLL
libqpdf/QUtil.cc
@@ -984,6 +984,32 @@ QUtil::qpdf_time_to_pdf_time(QPDFTime const&amp; qtm) @@ -984,6 +984,32 @@ QUtil::qpdf_time_to_pdf_time(QPDFTime const&amp; qtm)
984 QUtil::int_to_string(qtm.second, 2) + tz_offset); 984 QUtil::int_to_string(qtm.second, 2) + tz_offset);
985 } 985 }
986 986
  987 +std::string
  988 +QUtil::qpdf_time_to_iso8601(QPDFTime const& qtm)
  989 +{
  990 + std::string tz_offset;
  991 + int t = qtm.tz_delta;
  992 + if (t == 0) {
  993 + tz_offset = "Z";
  994 + } else {
  995 + if (t < 0) {
  996 + t = -t;
  997 + tz_offset += "+";
  998 + } else {
  999 + tz_offset += "-";
  1000 + }
  1001 + tz_offset += QUtil::int_to_string(t / 60, 2) + ":" +
  1002 + QUtil::int_to_string(t % 60, 2);
  1003 + }
  1004 + return (
  1005 + QUtil::int_to_string(qtm.year, 4) + "-" +
  1006 + QUtil::int_to_string(qtm.month, 2) + "-" +
  1007 + QUtil::int_to_string(qtm.day, 2) + "T" +
  1008 + QUtil::int_to_string(qtm.hour, 2) + ":" +
  1009 + QUtil::int_to_string(qtm.minute, 2) + ":" +
  1010 + QUtil::int_to_string(qtm.second, 2) + tz_offset);
  1011 +}
  1012 +
987 bool 1013 bool
988 QUtil::pdf_time_to_qpdf_time(std::string const& str, QPDFTime* qtm) 1014 QUtil::pdf_time_to_qpdf_time(std::string const& str, QPDFTime* qtm)
989 { 1015 {
@@ -1018,6 +1044,17 @@ QUtil::pdf_time_to_qpdf_time(std::string const&amp; str, QPDFTime* qtm) @@ -1018,6 +1044,17 @@ QUtil::pdf_time_to_qpdf_time(std::string const&amp; str, QPDFTime* qtm)
1018 return true; 1044 return true;
1019 } 1045 }
1020 1046
  1047 +bool
  1048 +QUtil::pdf_time_to_iso8601(std::string const& pdf_time, std::string& iso8601)
  1049 +{
  1050 + QPDFTime qtm;
  1051 + if (pdf_time_to_qpdf_time(pdf_time, &qtm)) {
  1052 + iso8601 = qpdf_time_to_iso8601(qtm);
  1053 + return true;
  1054 + }
  1055 + return false;
  1056 +}
  1057 +
1021 std::string 1058 std::string
1022 QUtil::toUTF8(unsigned long uval) 1059 QUtil::toUTF8(unsigned long uval)
1023 { 1060 {
libtests/qtest/qutil/qutil.out
@@ -127,7 +127,10 @@ rename over existing @@ -127,7 +127,10 @@ rename over existing
127 delete file 127 delete file
128 ---- timestamp 128 ---- timestamp
129 D:20210209144925-05'00' 129 D:20210209144925-05'00'
  130 +2021-02-09T14:49:25-05:00
130 D:20210210011925+05'30' 131 D:20210210011925+05'30'
  132 +2021-02-10T01:19:25+05:30
131 D:20210209191925Z 133 D:20210209191925Z
  134 +2021-02-09T19:19:25Z
132 ---- is_long_long 135 ---- is_long_long
133 done 136 done
libtests/qutil.cc
@@ -656,10 +656,14 @@ timestamp_test() @@ -656,10 +656,14 @@ timestamp_test()
656 { 656 {
657 auto check = [](QUtil::QPDFTime const& t) { 657 auto check = [](QUtil::QPDFTime const& t) {
658 std::string pdf = QUtil::qpdf_time_to_pdf_time(t); 658 std::string pdf = QUtil::qpdf_time_to_pdf_time(t);
659 - std::cout << pdf << std::endl; 659 + std::string iso8601 = QUtil::qpdf_time_to_iso8601(t);
  660 + std::cout << pdf << std::endl << iso8601 << std::endl;
660 QUtil::QPDFTime t2; 661 QUtil::QPDFTime t2;
  662 + std::string iso8601_2;
661 assert(QUtil::pdf_time_to_qpdf_time(pdf, &t2)); 663 assert(QUtil::pdf_time_to_qpdf_time(pdf, &t2));
662 assert(QUtil::qpdf_time_to_pdf_time(t2) == pdf); 664 assert(QUtil::qpdf_time_to_pdf_time(t2) == pdf);
  665 + assert(QUtil::pdf_time_to_iso8601(pdf, iso8601_2));
  666 + assert(iso8601 == iso8601_2);
663 }; 667 };
664 check(QUtil::QPDFTime(2021, 2, 9, 14, 49, 25, 300)); 668 check(QUtil::QPDFTime(2021, 2, 9, 14, 49, 25, 300));
665 check(QUtil::QPDFTime(2021, 2, 10, 1, 19, 25, -330)); 669 check(QUtil::QPDFTime(2021, 2, 10, 1, 19, 25, -330));