Skip to content

Commit 7d368c7

Browse files
committed
PDFBOX-6119: support dates without timezone + use jdk8, by Andrea Vacondio
git-svn-id: https://svn.apache.org/repos/asf/pdfbox/trunk@1930456 13f79535-47bb-0310-9956-ffa450edef68
1 parent bed1505 commit 7d368c7

File tree

2 files changed

+32
-89
lines changed

2 files changed

+32
-89
lines changed

xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java

Lines changed: 16 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@
2424
import java.io.IOException;
2525
import java.text.ParseException;
2626
import java.text.SimpleDateFormat;
27+
import java.time.LocalDateTime;
28+
import java.time.ZoneId;
2729
import java.time.ZonedDateTime;
2830
import java.time.format.DateTimeFormatter;
31+
import java.time.format.DateTimeFormatterBuilder;
2932
import java.time.format.DateTimeParseException;
3033
import java.util.Calendar;
3134
import java.util.Date;
3235
import java.util.GregorianCalendar;
3336
import java.util.Locale;
3437
import java.util.SimpleTimeZone;
3538
import java.util.TimeZone;
36-
import java.util.regex.Matcher;
3739
import java.util.regex.Pattern;
3840

3941
/**
@@ -52,6 +54,10 @@
5254
public final class DateConverter
5355
{
5456

57+
public static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder().parseCaseInsensitive()
58+
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME).parseLenient().appendOffset("+HH:MM", "Z").parseStrict()
59+
.toFormatter();
60+
5561
// The Date format is supposed to be the PDF_DATE_FORMAT, but not all PDF
5662
// documents
5763
// will use that date, so I have added a couple other potential formats
@@ -100,19 +106,10 @@ public static Calendar toCalendar(String date) throws IOException
100106
try
101107
{
102108
SimpleTimeZone zone = null;
103-
109+
104110
if (Pattern.matches("^\\d{4}-\\d{2}-\\d{2}T.*", date))
105111
{
106-
// Assuming ISO860 date string
107-
try
108-
{
109-
return fromISO8601(date, "yyyy-MM-dd'T'HH:mm:ss[.SSS][XXX][zzz]");
110-
}
111-
catch (DateTimeParseException e)
112-
{
113-
// PDFBOX-6062: support nanoseconds
114-
return fromISO8601(date, "yyyy-MM-dd'T'HH:mm:ss[.SSSSSS][XXX][zzz]");
115-
}
112+
return fromISO8601(date);
116113
}
117114
if (date.startsWith("D:"))
118115
{
@@ -339,77 +336,18 @@ public static String toISO8601(Calendar cal, boolean printMillis)
339336
retval.append(minutes);
340337
return retval.toString();
341338
}
342-
343-
/**
344-
* Get a Calendar from an ISO8601 date string.
345-
*
346-
* @param dateString
347-
* @return the Calendar instance.
348-
*/
349-
private static Calendar fromISO8601(String dateString, String pattern)
350-
{
351-
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
352-
353-
// Pattern to test for a time zone string
354-
Pattern timeZonePattern = Pattern.compile(
355-
"[\\d-]*T?[\\d-\\.]([A-Z]{1,4})$|(.*\\d*)([A-Z][a-z]+\\/[A-Z][a-z]+)$"
356-
);
357-
Matcher timeZoneMatcher = timeZonePattern.matcher(dateString);
358-
359-
String timeZoneString = null;
360-
361-
while (timeZoneMatcher.find())
362-
{
363-
for (int i = 1; i <= timeZoneMatcher.groupCount(); i++)
364-
{
365-
String group = timeZoneMatcher.group(i);
366-
if (group != null)
367-
{
368-
timeZoneString = group;
369-
}
370-
}
371-
}
372339

373-
if (timeZoneString != null)
340+
private static Calendar fromISO8601(String dateString)
341+
{
342+
try
374343
{
375-
// can't use parseDateTime immediately, first do handling for time that has no seconds
376-
int teeIndex = dateString.indexOf('T');
377-
int tzIndex = dateString.indexOf(timeZoneString);
378-
String toParse = dateString.substring(0, tzIndex);
379-
if (tzIndex - teeIndex == 6)
380-
{
381-
toParse = dateString.substring(0, tzIndex) + ":00";
382-
}
383-
384-
ZonedDateTime zonedDateTime = ZonedDateTime.parse(toParse + timeZoneString, dateTimeFormatter);
385-
344+
ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateString, DATE_TIME_FORMATTER);
386345
return GregorianCalendar.from(zonedDateTime);
387346
}
388-
else
347+
catch (DateTimeParseException e)
389348
{
390-
// can't use parseDateTime immediately, first do handling for time that has no seconds
391-
int teeIndex = dateString.indexOf('T');
392-
if (teeIndex == -1)
393-
{
394-
ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateString, dateTimeFormatter);
395-
return GregorianCalendar.from(zonedDateTime);
396-
}
397-
int plusIndex = dateString.indexOf('+', teeIndex + 1);
398-
int minusIndex = dateString.indexOf('-', teeIndex + 1);
399-
if (plusIndex == -1 && minusIndex == -1)
400-
{
401-
ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateString, dateTimeFormatter);
402-
return GregorianCalendar.from(zonedDateTime);
403-
}
404-
plusIndex = Math.max(plusIndex, minusIndex);
405-
if (plusIndex - teeIndex == 6)
406-
{
407-
String toParse = dateString.substring(0, plusIndex) + ":00" + dateString.substring(plusIndex);
408-
ZonedDateTime zonedDateTime = ZonedDateTime.parse(toParse, dateTimeFormatter);
409-
return GregorianCalendar.from(zonedDateTime);
410-
}
411-
ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateString, dateTimeFormatter);
412-
return GregorianCalendar.from(zonedDateTime);
349+
LocalDateTime localDateTime = LocalDateTime.parse(dateString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
350+
return GregorianCalendar.from(localDateTime.atZone(ZoneId.of("UTC")));
413351
}
414352
}
415353
}

xmpbox/src/test/java/org/apache/xmpbox/DateConverterTest.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@
2121

2222
package org.apache.xmpbox;
2323

24+
import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME;
25+
2426
import java.io.IOException;
2527

2628
import static org.junit.jupiter.api.Assertions.assertEquals;
2729
import static org.junit.jupiter.api.Assertions.assertThrows;
2830

2931
import java.text.SimpleDateFormat;
32+
import java.time.LocalDateTime;
33+
import java.time.ZoneId;
3034
import java.time.ZonedDateTime;
3135
import java.time.format.DateTimeFormatter;
3236
import java.util.Calendar;
@@ -53,8 +57,14 @@ class DateConverterTest
5357
void testDateConversion() throws IOException
5458
{
5559
// Test partial dates
56-
Calendar convDate = DateConverter.toCalendar("2015-02-02");
60+
Calendar convDate = DateConverter.toCalendar("2015");
61+
assertEquals(2015, convDate.get(Calendar.YEAR));
62+
convDate = DateConverter.toCalendar("2015-05");
63+
assertEquals(4, convDate.get(Calendar.MONTH));
64+
convDate = DateConverter.toCalendar("2015-05-02");
5765
assertEquals(2015, convDate.get(Calendar.YEAR));
66+
assertEquals(4, convDate.get(Calendar.MONTH));
67+
assertEquals(2, convDate.get(Calendar.DAY_OF_MONTH));
5868

5969
convDate = DateConverter.toCalendar("D:2015-02-02");
6070
assertEquals(2015, convDate.get(Calendar.YEAR));
@@ -133,16 +143,6 @@ void testDateConversion() throws IOException
133143

134144
assertEquals(DateConverter.toCalendar(testString2).toInstant(),ZonedDateTime.parse(testString1, dateTimeFormatter).toInstant());
135145

136-
testString1 = "2015-02-02T16:37:19.192Z";
137-
testString2 = "2015-02-02T08:37:19.192PST";
138-
139-
assertEquals(DateConverter.toCalendar(testString2).toInstant(),ZonedDateTime.parse(testString1, dateTimeFormatter).toInstant());
140-
141-
testString1 = "2015-02-02T16:37:19.192+01:00";
142-
testString2 = "2015-02-02T16:37:19.192Europe/Berlin";
143-
144-
assertEquals(DateConverter.toCalendar(testString2).toInstant(),ZonedDateTime.parse(testString1, dateTimeFormatter).toInstant());
145-
146146
// PDFBOX-4902: half-hour TZ
147147
testString1 = "2015-02-02T16:37:19.192+05:30";
148148
assertEquals(DateConverter.toCalendar(testString1).toInstant(),ZonedDateTime.parse(testString1, dateTimeFormatter).toInstant());
@@ -152,6 +152,11 @@ void testDateConversion() throws IOException
152152

153153
testString1 = "2015-02-02T16:37:19.192+10:30";
154154
assertEquals(DateConverter.toCalendar(testString1).toInstant(),ZonedDateTime.parse(testString1, dateTimeFormatter).toInstant());
155+
156+
testString1 = "2024-04-09T14:41:38";
157+
assertEquals(DateConverter.toCalendar(testString1).toInstant(),
158+
LocalDateTime.parse(testString1, ISO_LOCAL_DATE_TIME).atZone(ZoneId.of("UTC"))
159+
.toInstant());
155160
}
156161

157162
/**

0 commit comments

Comments
 (0)