urls = new ArrayList<>();
private final int maxUrls;
private final W3CDateFormat dateFormat;
- private final Date defaultLastMod;
+ private final OffsetDateTime defaultLastMod;
private final boolean autoValidate;
/** Options to configure sitemap index generation */
@@ -34,7 +36,7 @@ public static class Options {
private W3CDateFormat dateFormat = null;
private boolean allowEmptyIndex = false;
private int maxUrls = SitemapConstants.MAX_SITEMAPS_PER_INDEX;
- private Date defaultLastMod = new Date();
+ private OffsetDateTime defaultLastMod = OffsetDateTime.now();
private boolean autoValidate = false;
// TODO GZIP? Is that legal for a sitemap index?
@@ -55,7 +57,7 @@ public Options(URL baseUrl, File outFile) {
public Options(String baseUrl, File outFile) throws MalformedURLException {
this(new URL(baseUrl), outFile);
}
- /** The date formatter, typically configured with a {@link W3CDateFormat.Pattern} and/or a time zone */
+ /** The date formatter, typically configured with a {@link W3CDateFormat} and/or a time zone */
public Options dateFormat(W3CDateFormat dateFormat) {
this.dateFormat = dateFormat;
return this;
@@ -89,7 +91,7 @@ Options maxUrls(int maxUrls) {
* now, but you can pass in null to omit a lastMod entirely. We don't
* recommend this; Google may not like you as much.
*/
- public Options defaultLastMod(Date defaultLastMod) {
+ public Options defaultLastMod(OffsetDateTime defaultLastMod) {
this.defaultLastMod = defaultLastMod;
return this;
}
@@ -132,9 +134,9 @@ private SitemapIndexGenerator(Options options) {
this.outFile = options.outFile;
this.allowEmptyIndex = options.allowEmptyIndex;
this.maxUrls = options.maxUrls;
- W3CDateFormat dateFormat = options.dateFormat;
- if (dateFormat == null) dateFormat = new W3CDateFormat();
- this.dateFormat = dateFormat;
+ W3CDateFormat dateFormatter = options.dateFormat;
+ if (dateFormatter == null) dateFormatter = W3CDateFormat.AUTO;
+ this.dateFormat = dateFormatter;
this.defaultLastMod = options.defaultLastMod;
this.autoValidate = options.autoValidate;
}
@@ -184,12 +186,12 @@ public SitemapIndexGenerator addUrl(URL url) {
}
/** Adds a single sitemap to the index */
- public SitemapIndexGenerator addUrl(URL url, Date lastMod) {
+ public SitemapIndexGenerator addUrl(URL url, OffsetDateTime lastMod) {
return addUrl(new SitemapIndexUrl(url, lastMod));
}
/** Adds a single sitemap to the index */
- public SitemapIndexGenerator addUrl(String url, Date lastMod) throws MalformedURLException {
+ public SitemapIndexGenerator addUrl(String url, OffsetDateTime lastMod) throws MalformedURLException {
return addUrl(new SitemapIndexUrl(url, lastMod));
}
@@ -258,7 +260,7 @@ private void writeAsString(StringBuilder sb) {
sb.append(" ");
sb.append(UrlUtils.escapeXml(url.url.toString()));
sb.append("\n");
- Date lastMod = url.lastMod;
+ OffsetDateTime lastMod = url.lastMod;
if (lastMod == null) lastMod = defaultLastMod;
diff --git a/src/main/java/com/redfin/sitemapgenerator/SitemapIndexUrl.java b/src/main/java/com/redfin/sitemapgenerator/SitemapIndexUrl.java
index d19a953..d71ff5b 100644
--- a/src/main/java/com/redfin/sitemapgenerator/SitemapIndexUrl.java
+++ b/src/main/java/com/redfin/sitemapgenerator/SitemapIndexUrl.java
@@ -2,7 +2,7 @@
import java.net.MalformedURLException;
import java.net.URL;
-import java.util.Date;
+import java.time.OffsetDateTime;
/**
* Represents a single sitemap for inclusion in a sitemap index.
@@ -11,24 +11,24 @@
*/
public class SitemapIndexUrl {
final URL url;
- final Date lastMod;
+ final OffsetDateTime lastMod;
/** Configures the sitemap URL with a specified lastMod */
- public SitemapIndexUrl(URL url, Date lastMod) {
+ public SitemapIndexUrl(URL url, OffsetDateTime lastMod) {
this.url = url;
this.lastMod = lastMod;
}
/** Configures the sitemap URL with a specified lastMod */
- public SitemapIndexUrl(String url, Date lastMod) throws MalformedURLException {
+ public SitemapIndexUrl(String url, OffsetDateTime lastMod) throws MalformedURLException {
this(new URL(url), lastMod);
}
- /** Configures the sitemap URL with no specified lastMod; we'll use {@link SitemapIndexGenerator.Options#defaultLastMod(Date)} or leave it blank if no default is specified */
+ /** Configures the sitemap URL with no specified lastMod; we'll use {@link SitemapIndexGenerator.Options#defaultLastMod(OffsetDateTime)} or leave it blank if no default is specified */
public SitemapIndexUrl(URL url) {
this(url, null);
}
- /** Configures the sitemap URL with no specified lastMod; we'll use {@link SitemapIndexGenerator.Options#defaultLastMod(Date)} or leave it blank if no default is specified */
+ /** Configures the sitemap URL with no specified lastMod; we'll use {@link SitemapIndexGenerator.Options#defaultLastMod(OffsetDateTime)} or leave it blank if no default is specified */
public SitemapIndexUrl(String url) throws MalformedURLException {
this(new URL(url));
}
diff --git a/src/main/java/com/redfin/sitemapgenerator/W3CDateFormat.java b/src/main/java/com/redfin/sitemapgenerator/W3CDateFormat.java
index ce8a40c..a7ff277 100644
--- a/src/main/java/com/redfin/sitemapgenerator/W3CDateFormat.java
+++ b/src/main/java/com/redfin/sitemapgenerator/W3CDateFormat.java
@@ -1,29 +1,24 @@
/**
- *
+ *
*/
package com.redfin.sitemapgenerator;
-import java.text.DateFormat;
-import java.text.FieldPosition;
-import java.text.ParsePosition;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.GregorianCalendar;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.temporal.ChronoField;
+import java.util.Locale;
import java.util.Objects;
-import java.util.TimeZone;
-
-import static java.util.Calendar.HOUR_OF_DAY;
-import static java.util.Calendar.MILLISECOND;
-import static java.util.Calendar.MINUTE;
-import static java.util.Calendar.SECOND;
/**
* Formats and parses dates in the six defined W3C date time formats. These formats are described in
* "Date and Time Formats",
* https://www.w3.org/TR/NOTE-datetime.
- *
- * The formats are:
- *
+ *
+ *
The formats are:
+ *
*
* - YEAR: YYYY (eg 1997)
*
- MONTH: YYYY-MM (eg 1997-07)
@@ -32,157 +27,190 @@
*
- SECOND: YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
*
- MILLISECOND: YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
*
- *
- * Note that W3C timezone designators (TZD) are either the letter "Z" (for GMT) or a pattern like "+00:30" or "-08:00". This is unlike
+ *
+ * Note that W3C timezone designators (TZD) are either the letter "Z" (for GMT) or a pattern like "+00:30" or "-08:00". This is unlike
* RFC 822 timezones generated by SimpleDateFormat, which omit the ":" like this: "+0030" or "-0800".
- *
+ *
* This class allows you to either specify which format pattern to use, or (by default) to
* automatically guess which pattern to use (AUTO mode). When parsing in AUTO mode, we'll try parsing using each pattern
* until we find one that works. When formatting in AUTO mode, we'll use this algorithm:
- *
+ *
*
- If the date has fractional milliseconds (e.g. 2009-06-06T19:49:04.45Z) we'll use the MILLISECOND pattern
*
- Otherwise, if the date has non-zero seconds (e.g. 2009-06-06T19:49:04Z) we'll use the SECOND pattern
*
- Otherwise, if the date is not at exactly midnight (e.g. 2009-06-06T19:49Z) we'll use the MINUTE pattern
*
- Otherwise, we'll use the DAY pattern. If you want to format using the MONTH or YEAR pattern, you must declare it explicitly.
*
- *
- * Finally note that, like all classes that inherit from DateFormat, this class is not thread-safe. Also note that you
- * can explicitly specify the timezone to use for formatting using the {@link #setTimeZone(TimeZone)} method.
- *
+ *
* @author Dan Fabulich
* @see Date and Time Formats
*/
-public class W3CDateFormat extends SimpleDateFormat {
- private static final long serialVersionUID = -5733368073260485802L;
-
- /** The six patterns defined by W3C, plus {@link #AUTO} configuration */
- public enum Pattern {
- /** "yyyy-MM-dd'T'HH:mm:ss.SSSZ" */
- MILLISECOND("yyyy-MM-dd'T'HH:mm:ss.SSSZ", true),
- /** "yyyy-MM-dd'T'HH:mm:ssZ" */
- SECOND("yyyy-MM-dd'T'HH:mm:ssZ", true),
- /** "yyyy-MM-dd'T'HH:mmZ" */
- MINUTE("yyyy-MM-dd'T'HH:mmZ", true),
- /** "yyyy-MM-dd" */
- DAY("yyyy-MM-dd", false),
- /** "yyyy-MM" */
- MONTH("yyyy-MM", false),
- /** "yyyy" */
- YEAR("yyyy", false),
- /** Automatically compute the right pattern to use */
- AUTO("", true);
-
- private final String pattern;
- private final boolean includeTimeZone;
-
- Pattern(String pattern, boolean includeTimeZone) {
- this.pattern = pattern;
- this.includeTimeZone = includeTimeZone;
- }
- }
-
- private final Pattern pattern;
- /** The GMT ("zulu") time zone, for your convenience */
- public static final TimeZone ZULU = TimeZone.getTimeZone("GMT");
-
- /** Build a formatter in AUTO mode */
- public W3CDateFormat() {
- this(Pattern.AUTO);
- }
-
- /** Build a formatter using the specified Pattern, or AUTO mode */
- public W3CDateFormat(Pattern pattern) {
- super(pattern.pattern);
- this.pattern = pattern;
- }
-
- /** This is what you override when you extend DateFormat; use {@link DateFormat#format(Date)} instead */
- @Override
- public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {
- boolean includeTimeZone = pattern.includeTimeZone;
- if (pattern == Pattern.AUTO) {
- includeTimeZone = autoFormat(date);
- }
- super.format(date, toAppendTo, pos);
- if (includeTimeZone) convertRfc822TimeZoneToW3c(toAppendTo);
- return toAppendTo;
- }
-
- private boolean applyPattern(Pattern pattern) {
- applyPattern(pattern.pattern);
- return pattern.includeTimeZone;
- }
-
- private boolean autoFormat(Date date) {
- if (calendar == null) calendar = new GregorianCalendar();
- calendar.setTime(date);
- boolean hasMillis = calendar.get(MILLISECOND) > 0;
- if (hasMillis) {
- return applyPattern(Pattern.MILLISECOND);
- }
- boolean hasSeconds = calendar.get(SECOND) > 0;
- if (hasSeconds) {
- return applyPattern(Pattern.SECOND);
- }
- boolean hasTime = (calendar.get(HOUR_OF_DAY) + calendar.get(MINUTE)) > 0;
- if (hasTime) {
- return applyPattern(Pattern.MINUTE);
- }
- return applyPattern(Pattern.DAY);
- }
-
- /** This is what you override when you extend DateFormat; use {@link DateFormat#parse(String)} instead */
- @Override
- public Date parse(String text, ParsePosition pos) {
- text = convertW3cTimeZoneToRfc822(text);
- if (pattern == Pattern.AUTO) {
- return autoParse(text, pos);
- }
- return super.parse(text, pos);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof W3CDateFormat)) return false;
- if (!super.equals(o)) return false;
- W3CDateFormat that = (W3CDateFormat) o;
- return pattern == that.pattern;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(super.hashCode(), pattern);
- }
-
- private Date autoParse(String text, ParsePosition pos) {
- for (Pattern pattern : Pattern.values()) {
- if (pattern == Pattern.AUTO) continue;
- applyPattern(pattern);
- Date out = super.parse(text, pos);
- if (out != null) return out;
- }
- return null; // this will force a ParseException
- }
-
- private void convertRfc822TimeZoneToW3c(StringBuffer toAppendTo) {
- int length = toAppendTo.length();
- if (ZULU.equals(calendar.getTimeZone())) {
- toAppendTo.replace(length - 5, length, "Z");
- } else {
- toAppendTo.insert(length - 2, ':');
- }
- }
-
- private String convertW3cTimeZoneToRfc822(String source) {
- int length = source.length();
- if (source.endsWith("Z")) {
- return source.substring(0, length-1) + "+0000";
- }
- if (source.charAt(length-3) == ':') {
- return source.substring(0, length-3) + source.substring(length - 2);
- }
- return source;
- }
-
+public class W3CDateFormat {
+ public static final DateTimeFormatter FORMAT_RFC_822 = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz").withZone(ZoneOffset.UTC);
+
+ private static final DateTimeFormatter FORMAT_AUTO = new DateTimeFormatterBuilder()
+ .appendPattern("yyyy[-MM[-dd]]['T'HH[:mm[:ss[.SSS]]]][XXX]")
+ .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
+ .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
+ .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
+ .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
+ .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
+ .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
+ .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
+ .toFormatter(Locale.ENGLISH);
+ public static final W3CDateFormat AUTO = new W3CDateFormat(FORMAT_AUTO, true, ZoneOffset.UTC,true);
+
+ private static final DateTimeFormatter FORMAT_MILLISECONDS = new DateTimeFormatterBuilder()
+ .appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[XXX]")
+ .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
+ .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
+ .toFormatter(Locale.ENGLISH);
+ public static final W3CDateFormat MILLISECOND = new W3CDateFormat(FORMAT_MILLISECONDS, true, ZoneOffset.UTC);
+
+ private static final DateTimeFormatter FORMAT_SECONDS = new DateTimeFormatterBuilder()
+ .appendPattern("yyyy-MM-dd'T'HH:mm:ss[XXX]")
+ .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
+ .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
+ .toFormatter(Locale.ENGLISH);
+ public static final W3CDateFormat SECOND = new W3CDateFormat(FORMAT_SECONDS, true, ZoneOffset.UTC);
+
+ private static final DateTimeFormatter FORMAT_MINUTES = new DateTimeFormatterBuilder()
+ .appendPattern("yyyy-MM-dd'T'HH:mm[XXX]")
+ .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
+ .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
+ .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
+ .toFormatter(Locale.ENGLISH);
+ public static final W3CDateFormat MINUTE = new W3CDateFormat(FORMAT_MINUTES, true, ZoneOffset.UTC);
+
+ private static final DateTimeFormatter FORMAT_DAYS = new DateTimeFormatterBuilder()
+ .appendPattern("yyyy-MM-dd")
+ .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
+ .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
+ .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
+ .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
+ .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
+ .toFormatter(Locale.ENGLISH);
+ public static final W3CDateFormat DAY = new W3CDateFormat(FORMAT_DAYS, false, ZoneOffset.UTC);
+
+ private static final DateTimeFormatter FORMAT_MONTHS = new DateTimeFormatterBuilder()
+ .appendPattern("yyyy-MM")
+ .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
+ .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
+ .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
+ .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
+ .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
+ .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
+ .toFormatter(Locale.ENGLISH);
+ public static final W3CDateFormat MONTH = new W3CDateFormat(FORMAT_MONTHS, false, ZoneOffset.UTC);
+
+ private static final DateTimeFormatter FORMAT_YEAR = new DateTimeFormatterBuilder()
+ .appendPattern("yyyy")
+ .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
+ .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
+ .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
+ .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
+ .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
+ .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
+ .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
+ .toFormatter(Locale.ENGLISH);
+ public static final W3CDateFormat YEAR = new W3CDateFormat(FORMAT_YEAR, false, ZoneOffset.UTC);
+
+ private final DateTimeFormatter dateTimeFormatter;
+ private final boolean includeTimeZone;
+ private final ZoneId timeZone;
+ private final boolean isAuto;
+
+
+ public W3CDateFormat() {
+ this.dateTimeFormatter = FORMAT_AUTO;
+ this.isAuto = true;
+ this.includeTimeZone = true;
+ this.timeZone = ZoneOffset.UTC;
+ }
+
+ public W3CDateFormat(DateTimeFormatter formatter, boolean includeTimeZone, ZoneId zoneId) {
+ this.dateTimeFormatter = formatter;
+ this.includeTimeZone = includeTimeZone;
+ this.timeZone = zoneId;
+ this.isAuto = false;
+ }
+
+ private W3CDateFormat(DateTimeFormatter formatter, boolean includeTimeZone, ZoneId zoneId,boolean isAuto){
+ this.dateTimeFormatter = formatter;
+ this.includeTimeZone = includeTimeZone;
+ this.timeZone = zoneId;
+ this.isAuto = isAuto;
+ }
+
+ /**
+ * Parses a string representation of a date into an OffsetDateTime object using the configured DateTimeFormatter.
+ *
+ * @param date The date string to parse.
+ * @return The parsed OffsetDateTime object.
+ */
+ public OffsetDateTime parse(final String date) {
+ return OffsetDateTime.parse(date, dateTimeFormatter);
+ }
+
+ /**
+ * Creates a new W3CDateFormat with the specified ZoneId.
+ *
+ * @param zone the desired ZoneId
+ * @return a new instance of W3CDateFormat with the specified ZoneId
+ */
+ public W3CDateFormat withZone(final ZoneId zone) {
+ return new W3CDateFormat(dateTimeFormatter, includeTimeZone, zone,isAuto);
+ }
+
+ /**
+ * Formats the given OffsetDateTime object according to the configured settings.
+ *
+ * @param date The OffsetDateTime object to be formatted.
+ * @return The formatted date as a String.
+ */
+ public String format(OffsetDateTime date) {
+ if (!ZoneOffset.UTC.equals(timeZone)) {
+ date = date.atZoneSameInstant(timeZone).toOffsetDateTime();
+ }
+
+ DateTimeFormatter formatter = dateTimeFormatter;
+ if (isAuto) {
+ formatter = autoFormat(date);
+ }
+ if (includeTimeZone) {
+ return formatter.withZone(timeZone).format(date);
+ } else {
+ return formatter.format(date);
+ }
+
+ }
+
+
+ private DateTimeFormatter autoFormat(OffsetDateTime date) {
+ if (date.get(ChronoField.MILLI_OF_SECOND) > 0) {
+ return FORMAT_MILLISECONDS;
+ } else if (date.getSecond() > 0) {
+ return FORMAT_SECONDS;
+ } else if ((date.getHour() + date.getMinute()) > 0) {
+ return FORMAT_MINUTES;
+ } else {
+ return FORMAT_DAYS;
+ }
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof W3CDateFormat)) return false;
+ if (!super.equals(o)) return false;
+ W3CDateFormat that = (W3CDateFormat) o;
+ return dateTimeFormatter == that.dateTimeFormatter;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), dateTimeFormatter);
+ }
+
+
}
\ No newline at end of file
diff --git a/src/main/java/com/redfin/sitemapgenerator/WebSitemapUrl.java b/src/main/java/com/redfin/sitemapgenerator/WebSitemapUrl.java
index 0bcc504..7a099a4 100644
--- a/src/main/java/com/redfin/sitemapgenerator/WebSitemapUrl.java
+++ b/src/main/java/com/redfin/sitemapgenerator/WebSitemapUrl.java
@@ -2,7 +2,7 @@
import java.net.MalformedURLException;
import java.net.URL;
-import java.util.Date;
+import java.time.OffsetDateTime;
/**
* Encapsulates a single URL to be inserted into a Web sitemap (as opposed to a Geo sitemap, a Mobile sitemap, a Video sitemap, etc which are Google specific).
@@ -14,7 +14,7 @@
*/
public class WebSitemapUrl implements ISitemapUrl {
private final URL url;
- private final Date lastMod;
+ private final OffsetDateTime lastMod;
private final ChangeFreq changeFreq;
private final Double priority;
@@ -43,8 +43,10 @@ public WebSitemapUrl(Options options) {
this.priority = options.priority;
}
- /** Retrieves the {@link Options#lastMod(Date)} */
- public Date getLastMod() { return lastMod; }
+ /**
+ * Retrieves the {@link Options#lastMod(OffsetDateTime)}
+ */
+ public OffsetDateTime getLastMod() { return lastMod; }
/** Retrieves the {@link Options#changeFreq(ChangeFreq)} */
public ChangeFreq getChangeFreq() { return changeFreq; }
/** Retrieves the {@link Options#priority(Double)} */
diff --git a/src/test/java/com/redfin/sitemapgenerator/GoogleImageSitemapUrlTest.java b/src/test/java/com/redfin/sitemapgenerator/GoogleImageSitemapUrlTest.java
index 55ba63c..362d624 100644
--- a/src/test/java/com/redfin/sitemapgenerator/GoogleImageSitemapUrlTest.java
+++ b/src/test/java/com/redfin/sitemapgenerator/GoogleImageSitemapUrlTest.java
@@ -10,9 +10,7 @@
import java.util.ArrayList;
import java.util.List;
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.*;
class GoogleImageSitemapUrlTest {
diff --git a/src/test/java/com/redfin/sitemapgenerator/GoogleLinkSitemapUrlTest.java b/src/test/java/com/redfin/sitemapgenerator/GoogleLinkSitemapUrlTest.java
index 62d12ac..bd85d3a 100644
--- a/src/test/java/com/redfin/sitemapgenerator/GoogleLinkSitemapUrlTest.java
+++ b/src/test/java/com/redfin/sitemapgenerator/GoogleLinkSitemapUrlTest.java
@@ -1,7 +1,6 @@
package com.redfin.sitemapgenerator;
import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/com/redfin/sitemapgenerator/GoogleNewsSitemapUrlTest.java b/src/test/java/com/redfin/sitemapgenerator/GoogleNewsSitemapUrlTest.java
index 22faee8..50c30a3 100644
--- a/src/test/java/com/redfin/sitemapgenerator/GoogleNewsSitemapUrlTest.java
+++ b/src/test/java/com/redfin/sitemapgenerator/GoogleNewsSitemapUrlTest.java
@@ -1,12 +1,14 @@
package com.redfin.sitemapgenerator;
-import com.redfin.sitemapgenerator.W3CDateFormat.Pattern;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
-import java.util.Date;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -37,11 +39,9 @@ public void tearDown() {
@Test
void testSimpleUrl() throws Exception {
- W3CDateFormat dateFormat = new W3CDateFormat(Pattern.SECOND);
- dateFormat.setTimeZone(W3CDateFormat.ZULU);
wsg = GoogleNewsSitemapGenerator.builder("https://www.example.com", dir)
- .dateFormat(dateFormat).build();
- GoogleNewsSitemapUrl url = new GoogleNewsSitemapUrl("https://www.example.com/index.html", new Date(0), "Example Title", "The Example Times", "en");
+ .dateFormat(W3CDateFormat.SECOND.withZone(ZoneOffset.UTC)).build();
+ GoogleNewsSitemapUrl url = new GoogleNewsSitemapUrl("https://www.example.com/index.html", TestUtil.getEpochOffsetDateTime(), "Example Title", "The Example Times", "en");
wsg.addUrl(url);
String expected = "\n" +
String.format("\n",
@@ -64,11 +64,9 @@ void testSimpleUrl() throws Exception {
@Test
void testKeywords() throws Exception {
- W3CDateFormat dateFormat = new W3CDateFormat(Pattern.SECOND);
- dateFormat.setTimeZone(W3CDateFormat.ZULU);
wsg = GoogleNewsSitemapGenerator.builder("https://www.example.com", dir)
- .dateFormat(dateFormat).build();
- GoogleNewsSitemapUrl url = new GoogleNewsSitemapUrl.Options("https://www.example.com/index.html", new Date(0), "Example Title", "The Example Times", "en")
+ .dateFormat(W3CDateFormat.SECOND.withZone(ZoneOffset.UTC)).build();
+ GoogleNewsSitemapUrl url = new GoogleNewsSitemapUrl.Options("https://www.example.com/index.html", TestUtil.getEpochOffsetDateTime(), "Example Title", "The Example Times", "en")
.keywords("Klaatu", "Barrata", "Nicto")
.build();
wsg.addUrl(url);
@@ -94,11 +92,9 @@ void testKeywords() throws Exception {
@Test
void testGenres() throws Exception {
- W3CDateFormat dateFormat = new W3CDateFormat(Pattern.SECOND);
- dateFormat.setTimeZone(W3CDateFormat.ZULU);
wsg = GoogleNewsSitemapGenerator.builder("https://www.example.com", dir)
- .dateFormat(dateFormat).build();
- GoogleNewsSitemapUrl url = new GoogleNewsSitemapUrl.Options("https://www.example.com/index.html", new Date(0), "Example Title", "The Example Times", "en")
+ .dateFormat(W3CDateFormat.SECOND.withZone(ZoneOffset.UTC)).build();
+ GoogleNewsSitemapUrl url = new GoogleNewsSitemapUrl.Options("https://www.example.com/index.html", TestUtil.getEpochOffsetDateTime(), "Example Title", "The Example Times", "en")
.genres("persbericht")
.build();
wsg.addUrl(url);
diff --git a/src/test/java/com/redfin/sitemapgenerator/GoogleVideoSitemapUrlTest.java b/src/test/java/com/redfin/sitemapgenerator/GoogleVideoSitemapUrlTest.java
index 498e491..e9a6b69 100644
--- a/src/test/java/com/redfin/sitemapgenerator/GoogleVideoSitemapUrlTest.java
+++ b/src/test/java/com/redfin/sitemapgenerator/GoogleVideoSitemapUrlTest.java
@@ -8,7 +8,9 @@
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
-import java.util.Date;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -68,15 +70,13 @@ void testSimpleUrl() throws Exception {
@Test
void testOptions() throws Exception {
- W3CDateFormat dateFormat = new W3CDateFormat();
- dateFormat.setTimeZone(W3CDateFormat.ZULU);
wsg = GoogleVideoSitemapGenerator.builder("https://www.example.com", dir)
- .dateFormat(dateFormat).build();
+ .dateFormat(W3CDateFormat.AUTO.withZone(ZoneOffset.UTC)).build();
GoogleVideoSitemapUrl url = new Options(LANDING_URL, CONTENT_URL)
.playerUrl(new URL("https://www.example.com/index.swf"), true)
.thumbnailUrl(new URL("https://www.example.com/thumbnail.jpg"))
.title("This is a video!").description("A great video about dinosaurs")
- .rating(5.0).viewCount(500000).publicationDate(new Date(0)).tags("dinosaurs", "example", "awesome")
+ .rating(5.0).viewCount(500000).publicationDate(TestUtil.getEpochOffsetDateTime()).tags("dinosaurs", "example", "awesome")
.category("example").familyFriendly(false).durationInSeconds(60*30)
.build();
wsg.addUrl(url);
diff --git a/src/test/java/com/redfin/sitemapgenerator/SitemapGeneratorTest.java b/src/test/java/com/redfin/sitemapgenerator/SitemapGeneratorTest.java
index 9106cbb..3142fb7 100644
--- a/src/test/java/com/redfin/sitemapgenerator/SitemapGeneratorTest.java
+++ b/src/test/java/com/redfin/sitemapgenerator/SitemapGeneratorTest.java
@@ -9,14 +9,13 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
-import java.util.Date;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
import java.util.List;
import java.util.zip.GZIPInputStream;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertInstanceOf;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
class SitemapGeneratorTest {
@@ -151,11 +150,9 @@ void testTwoUrl() throws Exception {
@Test
void testAllUrlOptions() throws Exception {
- W3CDateFormat df = new W3CDateFormat();
- df.setTimeZone(W3CDateFormat.ZULU);
- wsg = WebSitemapGenerator.builder("https://www.example.com", dir).dateFormat(df).autoValidate(true).build();
+ wsg = WebSitemapGenerator.builder("https://www.example.com", dir).dateFormat(W3CDateFormat.AUTO.withZone(ZoneOffset.UTC)).autoValidate(true).build();
WebSitemapUrl url = new WebSitemapUrl.Options("https://www.example.com/index.html")
- .changeFreq(ChangeFreq.DAILY).lastMod(new Date(0)).priority(1.0).build();
+ .changeFreq(ChangeFreq.DAILY).lastMod(TestUtil.getEpochOffsetDateTime()).priority(1.0).build();
wsg.addUrl(url);
String expected = "\n" +
String.format("\n", SitemapConstants.SITEMAP_NS_URI) +
@@ -168,7 +165,7 @@ void testAllUrlOptions() throws Exception {
"";
String sitemap = writeSingleSiteMap(wsg);
assertEquals(expected, sitemap);
-
+
TestUtil.isValidSitemap(sitemap);
}
diff --git a/src/test/java/com/redfin/sitemapgenerator/SitemapIndexGeneratorTest.java b/src/test/java/com/redfin/sitemapgenerator/SitemapIndexGeneratorTest.java
index f819d54..78749dd 100644
--- a/src/test/java/com/redfin/sitemapgenerator/SitemapIndexGeneratorTest.java
+++ b/src/test/java/com/redfin/sitemapgenerator/SitemapIndexGeneratorTest.java
@@ -6,13 +6,15 @@
import java.io.File;
import java.net.MalformedURLException;
-import java.util.Date;
+import java.time.ZoneOffset;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class SitemapIndexGeneratorTest {
+ private static final W3CDateFormat ZULU = new W3CDateFormat().withZone(ZoneOffset.UTC);
+
private static final String INDEX = "\n" +
String.format("\n", SitemapConstants.SITEMAP_NS_URI) +
" \n" +
@@ -58,13 +60,11 @@ public class SitemapIndexGeneratorTest {
"";
private static final String EXAMPLE = "https://www.example.com/";
- private static final W3CDateFormat ZULU = new W3CDateFormat();
File outFile;
SitemapIndexGenerator sig;
@BeforeEach
public void setUp() throws Exception {
- ZULU.setTimeZone(W3CDateFormat.ZULU);
outFile = File.createTempFile(SitemapGeneratorTest.class.getSimpleName(), ".xml");
outFile.deleteOnExit();
}
@@ -106,7 +106,7 @@ void testNoUrlsEmptyIndexAllowed() throws Exception {
@Test
void testMaxUrls() throws Exception {
sig = new SitemapIndexGenerator.Options(EXAMPLE, outFile).autoValidate(true)
- .maxUrls(10).defaultLastMod(new Date(0)).dateFormat(ZULU).build();
+ .maxUrls(10).defaultLastMod(TestUtil.getEpochOffsetDateTime()).dateFormat(ZULU).build();
for (int i = 1; i <= 9; i++) {
sig.addUrl(EXAMPLE+"sitemap"+i+".xml");
}
@@ -120,7 +120,7 @@ void testMaxUrls() throws Exception {
@Test
void testOneUrl() throws Exception {
sig = new SitemapIndexGenerator.Options(EXAMPLE, outFile).dateFormat(ZULU).autoValidate(true).build();
- SitemapIndexUrl url = new SitemapIndexUrl(EXAMPLE+"index.html", new Date(0));
+ SitemapIndexUrl url = new SitemapIndexUrl(EXAMPLE+"index.html", TestUtil.getEpochOffsetDateTime());
sig.addUrl(url);
sig.write();
String actual = TestUtil.slurpFileAndDelete(outFile);
@@ -138,7 +138,7 @@ void testOneUrl() throws Exception {
@Test
void testAddByPrefix() throws MalformedURLException {
sig = new SitemapIndexGenerator.Options(EXAMPLE, outFile).autoValidate(true)
- .defaultLastMod(new Date(0)).dateFormat(ZULU).build();
+ .defaultLastMod(TestUtil.getEpochOffsetDateTime()).dateFormat(ZULU).build();
sig.addUrls("sitemap", ".xml", 10);
sig.write();
String actual = TestUtil.slurpFileAndDelete(outFile);
diff --git a/src/test/java/com/redfin/sitemapgenerator/TestUtil.java b/src/test/java/com/redfin/sitemapgenerator/TestUtil.java
index 2761fca..6239b48 100644
--- a/src/test/java/com/redfin/sitemapgenerator/TestUtil.java
+++ b/src/test/java/com/redfin/sitemapgenerator/TestUtil.java
@@ -11,6 +11,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -59,4 +62,8 @@ public static void isValidSitemap(String xml) {
ValidationResult vr = validator.validateInstance(Input.fromString(xml).build());
assertTrue(vr.isValid(), vr.getProblems().toString());
}
+
+ public static OffsetDateTime getEpochOffsetDateTime(){
+ return OffsetDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC);
+ }
}
diff --git a/src/test/java/com/redfin/sitemapgenerator/TutorialExampleTest.java b/src/test/java/com/redfin/sitemapgenerator/TutorialExampleTest.java
index a53ffa0..4287d12 100644
--- a/src/test/java/com/redfin/sitemapgenerator/TutorialExampleTest.java
+++ b/src/test/java/com/redfin/sitemapgenerator/TutorialExampleTest.java
@@ -1,12 +1,11 @@
package com.redfin.sitemapgenerator;
-import com.redfin.sitemapgenerator.W3CDateFormat.Pattern;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
-import java.util.Date;
+import java.time.OffsetDateTime;
import java.util.TimeZone;
public class TutorialExampleTest {
@@ -52,7 +51,7 @@ void testConfiguringWsgOptions() throws Exception {
void testConfiguringUrlOptions() throws Exception {
WebSitemapGenerator wsg = new WebSitemapGenerator("https://www.example.com", myDir);
WebSitemapUrl url = new WebSitemapUrl.Options("https://www.example.com/index.html")
- .lastMod(new Date()).priority(1.0).changeFreq(ChangeFreq.HOURLY).build();
+ .lastMod(OffsetDateTime.now()).priority(1.0).changeFreq(ChangeFreq.HOURLY).build();
// this will configure the URL with lastmod=now, priority=1.0, changefreq=hourly
wsg.addUrl(url);
wsg.write();
@@ -60,10 +59,8 @@ void testConfiguringUrlOptions() throws Exception {
@Test
void testConfiguringDateFormat() throws Exception {
- W3CDateFormat dateFormat = new W3CDateFormat(Pattern.DAY); // e.g. 2008-01-29
- dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); // Use Greenwich Mean Time timezone
WebSitemapGenerator wsg = WebSitemapGenerator.builder("https://www.example.com", myDir)
- .dateFormat(dateFormat).build(); // actually use the configured dateFormat
+ .dateFormat(W3CDateFormat.DAY.withZone(TimeZone.getTimeZone("GMT").toZoneId())).build(); // actually use the configured dateFormat
wsg.addUrl("https://www.example.com/index.html");
wsg.write();
}
diff --git a/src/test/java/com/redfin/sitemapgenerator/W3CDateFormatTest.java b/src/test/java/com/redfin/sitemapgenerator/W3CDateFormatTest.java
index b86b9d4..dfc3121 100644
--- a/src/test/java/com/redfin/sitemapgenerator/W3CDateFormatTest.java
+++ b/src/test/java/com/redfin/sitemapgenerator/W3CDateFormatTest.java
@@ -1,25 +1,21 @@
package com.redfin.sitemapgenerator;
-import com.redfin.sitemapgenerator.W3CDateFormat.Pattern;
import org.junit.jupiter.api.Test;
import java.text.ParseException;
-import java.util.Date;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.util.TimeZone;
-import static com.redfin.sitemapgenerator.W3CDateFormat.Pattern.AUTO;
-import static com.redfin.sitemapgenerator.W3CDateFormat.Pattern.DAY;
-import static com.redfin.sitemapgenerator.W3CDateFormat.Pattern.MILLISECOND;
-import static com.redfin.sitemapgenerator.W3CDateFormat.Pattern.MINUTE;
-import static com.redfin.sitemapgenerator.W3CDateFormat.Pattern.MONTH;
-import static com.redfin.sitemapgenerator.W3CDateFormat.Pattern.SECOND;
-import static com.redfin.sitemapgenerator.W3CDateFormat.Pattern.YEAR;
+import static com.redfin.sitemapgenerator.W3CDateFormat.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class W3CDateFormatTest {
@Test
void testFormatEpoch() {
- Date epoch = new Date(0);
+ OffsetDateTime epoch = TestUtil.getEpochOffsetDateTime();
verifyPatternFormat(epoch, MILLISECOND, "1970-01-01T00:00:00.000Z");
verifyPatternFormat(epoch, SECOND, "1970-01-01T00:00:00Z");
verifyPatternFormat(epoch, MINUTE, "1970-01-01T00:00Z");
@@ -31,29 +27,29 @@ void testFormatEpoch() {
@Test
void testAutoFormat() {
- Date date = new Date(0);
+ OffsetDateTime date = TestUtil.getEpochOffsetDateTime();
verifyPatternFormat(date, AUTO, "1970-01-01");
- date = new Date(1);
+ date = OffsetDateTime.ofInstant(Instant.ofEpochMilli(1), ZoneOffset.UTC);
verifyPatternFormat(date, AUTO, "1970-01-01T00:00:00.001Z");
- date = new Date(1000);
+ date = OffsetDateTime.ofInstant(Instant.ofEpochMilli(1000), ZoneOffset.UTC);
verifyPatternFormat(date, AUTO, "1970-01-01T00:00:01Z");
- date = new Date(60000);
+ date = OffsetDateTime.ofInstant(Instant.ofEpochMilli(60000), ZoneOffset.UTC);
verifyPatternFormat(date, AUTO, "1970-01-01T00:01Z");
- date = new Date(60000 * 60 * 24);
+ date = OffsetDateTime.ofInstant(Instant.ofEpochMilli(60000 * 60 * 24), ZoneOffset.UTC);
verifyPatternFormat(date, AUTO, "1970-01-02");
}
@Test
void testFormatTimeZone() {
- Date epoch = new Date(0);
- TimeZone tz = TimeZone.getTimeZone("PST");
- verifyPatternFormat(epoch, MILLISECOND, "1969-12-31T16:00:00.000-08:00", tz);
- verifyPatternFormat(epoch, AUTO, "1969-12-31T16:00-08:00", tz);
+ OffsetDateTime epoch = TestUtil.getEpochOffsetDateTime();
+ ZoneId tz = TimeZone.getTimeZone("PST").toZoneId();
+ verifyPatternFormat(epoch, MILLISECOND.withZone(tz), "1969-12-31T16:00:00.000-08:00", tz);
+ verifyPatternFormat(epoch, AUTO.withZone(tz), "1969-12-31T16:00-08:00", tz);
}
@Test
void testParseEpoch() throws ParseException {
- Date date = new Date(0);
+ OffsetDateTime date = TestUtil.getEpochOffsetDateTime();
verifyPatternParse("1970-01-01T00:00:00.000Z", MILLISECOND, date);
verifyPatternParse("1970-01-01T00:00:00Z", SECOND, date);
verifyPatternParse("1970-01-01T00:00Z", MINUTE, date);
@@ -65,7 +61,7 @@ void testParseEpoch() throws ParseException {
@Test
void testAutoParse() throws ParseException {
- Date date = new Date(0);
+ OffsetDateTime date = TestUtil.getEpochOffsetDateTime();
verifyPatternParse("1970-01-01T00:00:00.000Z", AUTO, date);
verifyPatternParse("1970-01-01T00:00:00Z", AUTO, date);
verifyPatternParse("1970-01-01T00:00Z", AUTO, date);
@@ -76,29 +72,26 @@ void testAutoParse() throws ParseException {
@Test
void testParseTimeZone() throws ParseException {
- Date epoch = new Date(0);
+ OffsetDateTime epoch = TestUtil.getEpochOffsetDateTime();
verifyPatternParse("1969-12-31T16:00:00.000-08:00", MILLISECOND, epoch);
verifyPatternParse("1969-12-31T16:00:00.000-08:00", AUTO, epoch);
}
- private void verifyPatternFormat(Date date, Pattern pattern, String expected) {
- verifyPatternFormat(date, pattern, expected, W3CDateFormat.ZULU);
+ private void verifyPatternFormat(OffsetDateTime date, W3CDateFormat pattern, String expected) {
+ verifyPatternFormat(date, pattern, expected, ZoneOffset.UTC);
}
- private void verifyPatternFormat(Date date, Pattern pattern, String expected, TimeZone tz) {
- W3CDateFormat format = new W3CDateFormat(pattern);
- format.setTimeZone(tz);
- assertEquals(expected, format.format(date), date.toString() + " " + pattern);
+ private void verifyPatternFormat(OffsetDateTime date, W3CDateFormat pattern, String expected, ZoneId tz) {
+
+ assertEquals(expected, pattern.format(date), date.toString() + " " + pattern);
}
- private void verifyPatternParse(String source, Pattern pattern, Date expected) throws ParseException {
- verifyPatternParse(source, pattern, expected, W3CDateFormat.ZULU);
+ private void verifyPatternParse(String source, W3CDateFormat pattern, OffsetDateTime expected) throws ParseException {
+ verifyPatternParse(source, pattern, expected, ZoneOffset.UTC);
}
- private void verifyPatternParse(String source, Pattern pattern, Date expected, TimeZone tz) throws ParseException {
- W3CDateFormat format = new W3CDateFormat(pattern);
- format.setTimeZone(tz);
- Date actual = format.parse(source);
+ private void verifyPatternParse(String source, W3CDateFormat pattern, OffsetDateTime expected, ZoneId tz) throws ParseException {
+ OffsetDateTime actual = pattern.parse(source).atZoneSameInstant(tz).toOffsetDateTime();
assertEquals(expected, actual, source + " " + pattern);
}