All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redfin.sitemapgenerator.W3CDateFormat Maven / Gradle / Ivy

The newest version!
/**
 * 
 */
package com.redfin.sitemapgenerator;

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;

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.util.TimeZone;

/**
 * 

Formats and parses dates in the six defined W3C date time formats. These formats are described in * "Date and Time Formats", * http://www.w3.org/TR/NOTE-datetime.

* *

The formats are: * *

    *
  1. YEAR: YYYY (eg 1997) *
  2. MONTH: YYYY-MM (eg 1997-07) *
  3. DAY: YYYY-MM-DD (eg 1997-07-16) *
  4. MINUTE: YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) *
  5. SECOND: YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) *
  6. 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 * 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: * *

  1. If the date has fractional milliseconds (e.g. 2009-06-06T19:49:04.45Z) we'll use the MILLISECOND pattern *
  2. Otherwise, if the date has non-zero seconds (e.g. 2009-06-06T19:49:04Z) we'll use the SECOND pattern *
  3. Otherwise, if the date is not at exactly midnight (e.g. 2009-06-06T19:49Z) we'll use the MINUTE pattern *
  4. 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); } 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy