package er.extensions.formatters; import java.text.DateFormatSymbols; import java.text.FieldPosition; import java.text.ParsePosition; import java.util.GregorianCalendar; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.webobjects.foundation.NSTimestamp; import com.webobjects.foundation.NSTimestampFormatter; /** * Date formatter that supports days with ordinal values like 1st, 2nd, 3rd. * etc. Not localized (English only at present). * * To include an ordinal suffix supply a format string that looks something like * this: "d'th' MMM, yyyy" where 'th' will be replaced by the correct ordinal * suffix. All standard NSTimestampFormatter tokens are supported. * * @author qdolan */ @SuppressWarnings("deprecation") public class ERXOrdinalDateFormatter extends NSTimestampFormatter { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; private final Pattern ORDINAL_PATTERN = Pattern.compile("(?:([1-3]?[0-9])(?:st|nd|rd|th))"); public ERXOrdinalDateFormatter() { super(); } public ERXOrdinalDateFormatter(String aPattern) { super(aPattern); } public ERXOrdinalDateFormatter(String aPattern, DateFormatSymbols symbols) { super(aPattern, symbols); } @Override public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { NSTimestamp timestamp; if (obj instanceof NSTimestamp) timestamp = (NSTimestamp) obj; else if (obj instanceof java.util.Date) timestamp = new NSTimestamp((java.util.Date) obj); else if (obj instanceof java.sql.Date) timestamp = new NSTimestamp((java.sql.Date) obj); else throw new IllegalArgumentException("Unable to format " + obj.getClass() + " : " + obj.toString()); String formatted = super.format(timestamp, new StringBuffer(), pos).toString(); Matcher matcher = ORDINAL_PATTERN.matcher(formatted); if (pattern().contains("'th") && matcher.find()) { formatted = matcher.replaceAll("$1" + ordinalSuffix(timestamp)); } return toAppendTo.append(formatted); } private String ordinalSuffix(NSTimestamp timestamp) { GregorianCalendar calendar = new GregorianCalendar(); calendar.setTimeZone(defaultFormatTimeZone()); calendar.setTime(timestamp); switch (calendar.get(GregorianCalendar.DAY_OF_MONTH)) { case 1: case 21: case 31: return "st"; case 2: case 22: return "nd"; case 3: case 23: return "rd"; default: return "th"; } } @Override public Object parseObject(String source, ParsePosition pos) { Matcher matcher = ORDINAL_PATTERN.matcher(source); return super.parseObject(matcher.replaceAll("$1th"), pos); } }