diff options
| -rw-r--r-- | htroot/CrawlResults.java | 14 | ||||
| -rw-r--r-- | htroot/IndexCreateQueues_p.java | 18 | ||||
| -rw-r--r-- | source/net/yacy/cora/document/feed/RSSMessage.java | 11 | ||||
| -rw-r--r-- | source/net/yacy/cora/protocol/HeaderFramework.java | 66 | ||||
| -rw-r--r-- | test/java/net/yacy/cora/protocol/HeaderFrameworkTest.java | 51 |
5 files changed, 144 insertions, 16 deletions
diff --git a/htroot/CrawlResults.java b/htroot/CrawlResults.java index ef9c2312b..3429ac31b 100644 --- a/htroot/CrawlResults.java +++ b/htroot/CrawlResults.java @@ -24,7 +24,8 @@ // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import java.text.SimpleDateFormat;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
@@ -34,6 +35,7 @@ import java.util.Locale; import java.util.Map;
import java.util.Set;
+import net.yacy.cora.date.GenericFormatter;
import net.yacy.cora.document.encoding.ASCII;
import net.yacy.cora.document.encoding.UTF8;
import net.yacy.cora.document.id.Punycode.PunycodeException;
@@ -350,11 +352,17 @@ public class CrawlResults { return prop;
}
- private static SimpleDateFormat dayFormatter = new SimpleDateFormat("yyyy/MM/dd", Locale.US);
+ private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter
+ .ofPattern("uuuu/MM/dd", Locale.US).withZone(ZoneId.systemDefault());
+
+ /**
+ * @param date a date to render as a String
+ * @return the date formatted using the DAY_FORMATTER pattern.
+ */
private static String daydate(final Date date) {
if (date == null) {
return "";
}
- return dayFormatter.format(date);
+ return GenericFormatter.formatSafely(date.toInstant(), DAY_FORMATTER);
}
}
diff --git a/htroot/IndexCreateQueues_p.java b/htroot/IndexCreateQueues_p.java index 393889daf..96c135067 100644 --- a/htroot/IndexCreateQueues_p.java +++ b/htroot/IndexCreateQueues_p.java @@ -1,6 +1,7 @@ import java.net.MalformedURLException; -import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; @@ -12,6 +13,7 @@ import java.util.Set; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import net.yacy.cora.date.GenericFormatter; import net.yacy.cora.document.encoding.ASCII; import net.yacy.cora.document.id.DigestURL; import net.yacy.cora.protocol.Domains; @@ -28,10 +30,18 @@ import net.yacy.server.serverSwitch; public class IndexCreateQueues_p { - private static SimpleDateFormat dayFormatter = new SimpleDateFormat("yyyy/MM/dd", Locale.US); + private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter + .ofPattern("uuuu/MM/dd", Locale.US).withZone(ZoneId.systemDefault()); + + /** + * @param date a date to render as a String + * @return the date formatted using the DAY_FORMATTER pattern. + */ private static String daydate(final Date date) { - if (date == null) return ""; - return dayFormatter.format(date); + if (date == null) { + return ""; + } + return GenericFormatter.formatSafely(date.toInstant(), DAY_FORMATTER); } private static final int INVALID = 0; diff --git a/source/net/yacy/cora/document/feed/RSSMessage.java b/source/net/yacy/cora/document/feed/RSSMessage.java index a12768a24..8906d103b 100644 --- a/source/net/yacy/cora/document/feed/RSSMessage.java +++ b/source/net/yacy/cora/document/feed/RSSMessage.java @@ -25,6 +25,7 @@ package net.yacy.cora.document.feed; import java.text.ParseException; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -156,7 +157,7 @@ public class RSSMessage implements Hit, Comparable<RSSMessage>, Comparator<RSSMe if (title.length() > 0) this.map.put(Token.title.name(), title); if (description.length() > 0) this.map.put(Token.description.name(), description); if (link.length() > 0) this.map.put(Token.link.name(), link); - this.map.put(Token.pubDate.name(), HeaderFramework.FORMAT_RFC1123.format(new Date())); + this.map.put(Token.pubDate.name(), HeaderFramework.formatNowRFC1123()); this.map.put(Token.guid.name(), artificialGuidPrefix + Integer.toHexString((title + description + link).hashCode())); } @@ -165,7 +166,7 @@ public class RSSMessage implements Hit, Comparable<RSSMessage>, Comparator<RSSMe if (title.length() > 0) this.map.put(Token.title.name(), title); if (description.length() > 0) this.map.put(Token.description.name(), description); this.map.put(Token.link.name(), link.toNormalform(true)); - this.map.put(Token.pubDate.name(), HeaderFramework.FORMAT_RFC1123.format(new Date())); + this.map.put(Token.pubDate.name(), HeaderFramework.formatNowRFC1123()); if (guid.length() > 0) { this.map.put(Token.guid.name(), guid); } @@ -261,8 +262,8 @@ public class RSSMessage implements Hit, Comparable<RSSMessage>, Comparator<RSSMe if (!dateString.isEmpty()) { // skip parse exception on empty string Date date; try { - date = HeaderFramework.FORMAT_RFC1123.parse(dateString); - } catch (final ParseException e) { + date = Date.from(ZonedDateTime.parse(dateString, HeaderFramework.RFC1123_FORMATTER).toInstant()); + } catch (final RuntimeException e) { try { date = GenericFormatter.SHORT_SECOND_FORMATTER.parse(dateString, 0).getTime(); } catch (final ParseException e1) { @@ -401,7 +402,7 @@ public class RSSMessage implements Hit, Comparable<RSSMessage>, Comparator<RSSMe @Override public void setPubDate(final Date pubdate) { - setValue(Token.pubDate, HeaderFramework.FORMAT_RFC1123.format(pubdate)); + setValue(Token.pubDate, HeaderFramework.formatNowRFC1123()); } @Override diff --git a/source/net/yacy/cora/protocol/HeaderFramework.java b/source/net/yacy/cora/protocol/HeaderFramework.java index 3595cc933..0eeb3ddf2 100644 --- a/source/net/yacy/cora/protocol/HeaderFramework.java +++ b/source/net/yacy/cora/protocol/HeaderFramework.java @@ -26,6 +26,10 @@ import java.io.FileOutputStream; import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
@@ -230,10 +234,33 @@ public class HeaderFramework extends TreeMap<String, String> implements Map<Stri /** Date formatter/parser for standard compliant HTTP header dates (RFC 1123) */
private static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss Z"; // with numeric time zone indicator as defined in RFC5322
private static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
- public static final SimpleDateFormat FORMAT_RFC1123 = new SimpleDateFormat(PATTERN_RFC1123, Locale.US);
- public static final SimpleDateFormat FORMAT_RFC1036 = new SimpleDateFormat(PATTERN_RFC1036, Locale.US);
+ private static final SimpleDateFormat FORMAT_RFC1123 = new SimpleDateFormat(PATTERN_RFC1123, Locale.US);
private static final TimeZone TZ_GMT = TimeZone.getTimeZone("GMT");
private static final Calendar CAL_GMT = Calendar.getInstance(TZ_GMT, Locale.US);
+
+ /**
+ * A thread-safe date formatter using the
+ * {@link HeaderFramework#PATTERN_RFC1123} pattern with the US locale on the UTC
+ * time zone.
+ */
+ public static final DateTimeFormatter RFC1123_FORMATTER = DateTimeFormatter
+ .ofPattern(PATTERN_RFC1123.replace("yyyy", "uuuu")).withLocale(Locale.US).withZone(ZoneOffset.UTC);
+
+ /**
+ * @return a new SimpleDateFormat instance using the
+ * {@link HeaderFramework#PATTERN_RFC1123} pattern with the US locale.
+ */
+ public static SimpleDateFormat newRfc1123Format() {
+ return new SimpleDateFormat(HeaderFramework.PATTERN_RFC1123, Locale.US);
+ }
+
+ /**
+ * @return a new SimpleDateFormat instance using the
+ * {@link HeaderFramework#PATTERN_RFC1036} pattern with the US locale.
+ */
+ public static SimpleDateFormat newRfc1036Format() {
+ return new SimpleDateFormat(HeaderFramework.PATTERN_RFC1036, Locale.US);
+ }
/**
* RFC 2616 requires that HTTP clients are able to parse all 3 different
@@ -241,9 +268,9 @@ public class HeaderFramework extends TreeMap<String, String> implements Map<Stri */
private static final SimpleDateFormat[] FORMATS_HTTP = new SimpleDateFormat[] {
// RFC 1123/822 (Standard) "Mon, 12 Nov 2007 10:11:12 GMT"
- FORMAT_RFC1123,
+ newRfc1123Format(),
// RFC 1036/850 (old) "Monday, 12-Nov-07 10:11:12 GMT"
- FORMAT_RFC1036,
+ newRfc1036Format(),
// ANSI C asctime() "Mon Nov 12 10:11:12 2007"
GenericFormatter.newAnsicFormat(),
};
@@ -265,6 +292,34 @@ public class HeaderFramework extends TreeMap<String, String> implements Map<Stri return s;
}
}
+
+ /**
+ * @param epochMilli
+ * a time value as the number of milliseconds from Epoch
+ * (1970-01-01T00:00:00Z)
+ * @return the time formatted using the {@link HeaderFramework#PATTERN_RFC1123}
+ * pattern.
+ */
+ public static final String formatRFC1123(final long epochMilli) {
+ try {
+ /* Prefer first using the thread-safe DateTimeFormatter shared instance */
+ return RFC1123_FORMATTER.format(Instant.ofEpochMilli(epochMilli));
+ } catch (final DateTimeException e) {
+ /*
+ * This should not happen, but rather than failing we prefer here to use
+ * formatting function using the synchronized SimpleDateFormat
+ */
+ return formatRFC1123(new Date(epochMilli));
+ }
+ }
+
+ /**
+ * @return the current time formatted using the
+ * {@link HeaderFramework#PATTERN_RFC1123} pattern.
+ */
+ public static final String formatNowRFC1123() {
+ return formatRFC1123(System.currentTimeMillis());
+ }
/** Initialization of static formats */
static {
@@ -277,6 +332,9 @@ public class HeaderFramework extends TreeMap<String, String> implements Map<Stri format.setTimeZone(TZ_GMT);
format.set2DigitYearStart(CAL_GMT.getTime());
}
+
+ FORMAT_RFC1123.setTimeZone(TZ_GMT);
+ FORMAT_RFC1123.set2DigitYearStart(CAL_GMT.getTime());
}
/**
diff --git a/test/java/net/yacy/cora/protocol/HeaderFrameworkTest.java b/test/java/net/yacy/cora/protocol/HeaderFrameworkTest.java index 71d013698..971dc57ad 100644 --- a/test/java/net/yacy/cora/protocol/HeaderFrameworkTest.java +++ b/test/java/net/yacy/cora/protocol/HeaderFrameworkTest.java @@ -1,6 +1,29 @@ +// HeaderFrameworkTest.java +// Copyright 2006-2018 by theli, f1ori, Michael Peter Christen; mc@yacy.net, reger; reger18@arcor.de, luccioman; https://github.com/luccioman +// +// This is a part of YaCy, a peer-to-peer based web search engine +// +// LICENSE +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + package net.yacy.cora.protocol; +import java.time.Instant; import java.util.Date; + import junit.framework.TestCase; import org.junit.Test; @@ -18,6 +41,22 @@ public class HeaderFrameworkTest extends TestCase { // Print Result System.out.println("testParseHTTPDate: " + parsedDate.toString()); + + parsedDate = HeaderFramework.parseHTTPDate("Monday, 12-Nov-07 10:11:12 GMT"); + + // returned date must not be null + assertNotNull(parsedDate); + + // Print Result + System.out.println("testParseHTTPDate: " + parsedDate.toString()); + + parsedDate = HeaderFramework.parseHTTPDate("Mon Nov 12 10:11:12 2007"); + + // returned date must not be null + assertNotNull(parsedDate); + + // Print Result + System.out.println("testParseHTTPDate: " + parsedDate.toString()); } /** @@ -31,4 +70,16 @@ public class HeaderFrameworkTest extends TestCase { assertEquals("utf-8", HeaderFramework.getCharacterEncoding("Text/HTML;Charset=\"utf-8\"")); assertEquals("utf-8", HeaderFramework.getCharacterEncoding("text/html; charset=\"utf-8\"")); } + + /** + * Unit test for date formatting with RFC 1123 format + */ + @Test + public void testFormatRfc1123() { + assertEquals("", HeaderFramework.formatRFC1123(null)); + + final Instant time = Instant.parse("2018-06-29T13:04:55.00Z"); + assertEquals("Fri, 29 Jun 2018 13:04:55 +0000", HeaderFramework.formatRFC1123(time.toEpochMilli())); + assertEquals("Fri, 29 Jun 2018 13:04:55 +0000", HeaderFramework.formatRFC1123(Date.from(time))); + } } |
