org.fcrepo.server.utilities.DateUtility.java Source code

Java tutorial

Introduction

Here is the source code for org.fcrepo.server.utilities.DateUtility.java

Source

/* The contents of this file are subject to the license and copyright terms
 * detailed in the license directory at the root of the source tree (also
 * available online at http://fedora-commons.org/license/).
 */
package org.fcrepo.server.utilities;

import java.text.ParseException;
import java.util.Date;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

/**
 * A collection of utility methods for performing frequently required tasks.
 * 
 * @author Ross Wayland
 * @author Frank Asseg
 */
public abstract class DateUtility {

    //   private static final Date ONE_BCE = new Date(-62198755200000L);

    private static final Date ONE_CE = new Date(-62135596800000L);

    private static final DateTimeFormatter FORMATTER_MILLISECONDS_T_Z = DateTimeFormat
            .forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    private static final DateTimeFormatter FORMATTER_MILLISECONDS_T = DateTimeFormat
            .forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
    private static final DateTimeFormatter FORMATTER_SECONDS_T_Z = DateTimeFormat
            .forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
    private static final DateTimeFormatter FORMATTER_SECONDS_T = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
    private static final DateTimeFormatter FORMATTER_SECONDS_Z = DateTimeFormat.forPattern("HH:mm:ss.SSS'Z'");
    private static final DateTimeFormatter FORMATTER_DATE_Z = DateTimeFormat.forPattern("yyyy-MM-dd'Z'");
    private static final DateTimeFormatter FORMATTER_DATE = DateTimeFormat.forPattern("yyyy-MM-dd");
    private static final DateTimeFormatter FORMATTER_TIMEZONE = DateTimeFormat
            .forPattern("EEE, dd MMMM yyyyy HH:mm:ss");

    static {
        DateTimeZone.setDefault(DateTimeZone.UTC);
    }

    /**
     * Converts a datetime string into and instance of java.util.Date using the
     * date format: yyyy-MM-ddTHH:mm:ss.SSSZ.
     * 
     * @param dateTime
     *            A datetime string
     * @return Corresponding instance of java.util.Date (returns null if
     *         dateTime string argument is empty string or null)
     */
    public static Date convertStringToDate(String dateTime) {
        return parseDateLoose(dateTime);
    }

    /**
     * Converts an instance of java.util.Date into a String using the date
     * format: yyyy-MM-ddTHH:mm:ss.SSSZ.
     * 
     * @param date
     *            Instance of java.util.Date.
     * @return ISO 8601 String representation (yyyy-MM-ddTHH:mm:ss.SSSZ) of the
     *         Date argument or null if the Date argument is null.
     */
    public static String convertDateToString(Date date) {
        return convertDateToString(date, true);
    }

    /**
     * Converts an instance of java.util.Date into an ISO 8601 String
     * representation. Uses the date format yyyy-MM-ddTHH:mm:ss.SSSZ or
     * yyyy-MM-ddTHH:mm:ssZ, depending on whether millisecond precision is
     * desired.
     * 
     * @param date
     *            Instance of java.util.Date.
     * @param millis
     *            Whether or not the return value should include milliseconds.
     * @return ISO 8601 String representation of the Date argument or null if
     *         the Date argument is null.
     */
    public static String convertDateToString(Date date, boolean millis) {
        if (date == null) {
            return null;
        } else {
            DateTimeFormatter df;
            if (millis) {
                // df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                df = FORMATTER_MILLISECONDS_T_Z;
            } else {
                // df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                df = FORMATTER_SECONDS_T_Z;
            }

            return df.print(date.getTime());
        }
    }

    /**
     * Converts an instance of <code>Date</code> into the canonical lexical
     * representation of an XSD dateTime with the following exceptions: - Dates
     * before 1 CE (i.e. 1 AD) are handled according to ISO 8601:2000 Second
     * Edition: "0000" is the lexical representation of 1 BCE "-0001" is the
     * lexical representation of 2 BCE
     * 
     * @param date
     *            Instance of java.util.Date.
     * @return the lexical form of the XSD dateTime value, e.g.
     *         "2006-11-13T09:40:55.001Z".
     * @see <a
     *      href="http://www.w3.org/TR/xmlschema-2/#date-canonical-representation">3.2.7.2
     *      Canonical representation</a>
     */
    public static String convertDateToXSDString(Date date) {
        if (date == null) {
            return null;
        }
        String dateTime = convertDateToString(date, true);
        if (date.before(ONE_CE)) {
            // fix the format for lexical representation of the year
            // e.g. 1 BCE: 0000-01.01 (1BCE is year 0)
            int pos = dateTime.indexOf('-', 1);
            int year = Integer.parseInt(dateTime.substring(0, pos));
            if (year == -1) {
                dateTime = "0000" + dateTime.substring(pos);
            } else if (year < 0) {
                year += 1;
                String prefix = "";
                if (year > -10) {
                    prefix = "000";
                } else if (year > -100) {
                    prefix = "00";
                } else if (year > -1000) {
                    prefix = "0";
                }
                dateTime = "-" + prefix + Math.abs(year) + dateTime.substring(pos);
            }
        }
        // fix the format for the lexical representation of the milliseconds,
        // no leading 0s are allowed, and if it's all zeros it has to be
        // removed.
        int posDot = dateTime.indexOf('.');
        int posZ = dateTime.indexOf('Z');
        int millis = Integer.parseInt(dateTime.substring(posDot + 1, posZ));
        String milliString;
        if (millis == 0) {
            milliString = "";
        } else if (millis < 10) {
            milliString = ".00" + millis;
        } else if (millis < 100) {
            milliString = ".0" + millis;
        } else {
            milliString = "." + millis;
        }
        while (milliString.length() > 0 && milliString.charAt(milliString.length() - 1) == '0') {
            milliString = milliString.substring(0, milliString.length() - 1);
        }
        dateTime = dateTime.substring(0, posDot) + milliString + "Z";
        return dateTime;
    }

    /**
     * Converts an instance of java.util.Date into a String using the date
     * format: yyyy-MM-ddZ.
     * 
     * @param date
     *            Instance of java.util.Date.
     * @return Corresponding date string (returns null if Date argument is
     *         null).
     */
    public static String convertDateToDateString(Date date) {
        if (date == null) {
            return null;
        } else {
            // DateFormat df = new SimpleDateFormat("yyyy-MM-dd'Z'");
            DateTimeFormatter df = FORMATTER_DATE_Z;
            return df.print(date.getTime());
        }
    }

    /**
     * Converts an instance of java.util.Date into a String using the date
     * format: HH:mm:ss.SSSZ.
     * 
     * @param date
     *            Instance of java.util.Date.
     * @return Corresponding time string (returns null if Date argument is
     *         null).
     */
    public static String convertDateToTimeString(Date date) {
        if (date == null) {
            return null;
        } else {
            // DateFormat df = new SimpleDateFormat("HH:mm:ss.SSS'Z'");
            DateTimeFormatter df = FORMATTER_SECONDS_Z;
            return df.print(date.getTime());
        }
    }

    /**
     * Convenience method for {@link #parseDateStrict(String)} which does not
     * throw an exception on error, but merely returns null.
     * 
     * @param dateString
     *            the date string to parse
     * @return Date the date, if parse was successful; null otherwise
     */
    public static Date parseDateLoose(String dateString) {
        try {
            return parseDateStrict(dateString);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * Convenience method for {@link #parseDateStrict(String)} with the
     * following difference: null or empty input returns null. Any other parse
     * errors are wrapped as an IllegalArgumentException.
     * 
     * @param dateString
     *            the date string to parse
     * @return a Date representation of the dateString or null
     * @throws IllegalArgumentException
     *             if dateString is unable to be parsed.
     */
    public static Date parseDateOrNull(String dateString) throws IllegalArgumentException {
        if (dateString == null) {
            return null;
        } else if (dateString.isEmpty()) {
            return null;
        }
        try {
            return parseDateStrict(dateString);
        } catch (ParseException e) {
            throw new IllegalArgumentException(e.getMessage(), e);
        }
    }

    /**
     * Attempt to parse the given string of form: yyyy-MM-dd[THH:mm:ss[.SSS][Z]]
     * as a Date.
     * 
     * @param dateString
     *            the date string to parse
     * @return a Date representation of the dateString
     * @throws ParseException
     *             if dateString is null, empty or is otherwise unable to be
     *             parsed.
     */
    public static Date parseDateStrict(String dateString) throws ParseException {
        try {
            if (dateString == null) {
                throw new ParseException("Argument cannot be null.", 0);
            }

            final int last = dateString.length() - 1;
            if (last == -1) {
                throw new ParseException("Argument cannot be empty.", 0);
            } else if (dateString.charAt(last) == '.') {
                throw new ParseException("dateString ends with invalid character.", last);
            }
            // SimpleDateFormat formatter = new SimpleDateFormat();
            // formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
            final int length = (dateString.charAt(0) != '-') ? last + 1 : last;
            DateTimeFormatter formatter = FORMATTER_MILLISECONDS_T_Z;
            if (dateString.charAt(last) == 'Z') {
                if (length == 11) {
                    // formatter.applyPattern("yyyy-MM-dd'Z'");
                    formatter = FORMATTER_DATE_Z;
                } else if (length == 20) {
                    // formatter.applyPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
                    formatter = FORMATTER_SECONDS_T_Z;
                } else if (length > 21 && length < 24) {
                    // right-pad the milliseconds with 0s up to three places
                    int endIndex = last - 1;
                    int dotIndex = dateString.lastIndexOf('.');
                    int padding = 3 - (endIndex - dotIndex);
                    if (padding > 0) {
                        StringBuilder sb = new StringBuilder(24);
                        sb.append(dateString.subSequence(0, last));
                        switch (padding) {
                        case 3:
                            sb.append('0');
                        case 2:
                            sb.append('0');
                        case 1:
                            sb.append('0');
                        }
                        sb.append('Z');
                        dateString = sb.toString();
                    }
                    // formatter.applyPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                    formatter = FORMATTER_MILLISECONDS_T_Z;
                } else if (length == 24) {
                    // formatter.applyPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                    formatter = FORMATTER_MILLISECONDS_T_Z;
                }
            } else {
                if (length == 10) {
                    // formatter.applyPattern("yyyy-MM-dd");
                    formatter = FORMATTER_DATE;
                } else if (length == 19) {
                    // formatter.applyPattern("yyyy-MM-dd'T'HH:mm:ss");
                    formatter = FORMATTER_SECONDS_T;
                } else if (length > 20 && length < 23) {
                    // right-pad millis with 0s
                    int endIndex = dateString.length() - 1;
                    int dotIndex = dateString.lastIndexOf('.');
                    int padding = 3 - (endIndex - dotIndex);
                    if (padding > 0) {
                        StringBuilder sb = new StringBuilder(23);
                        sb.append(dateString);
                        switch (padding) {
                        case 3:
                            sb.append('0');
                        case 2:
                            sb.append('0');
                        case 1:
                            sb.append('0');
                        }
                        dateString = sb.toString();
                    }
                    // formatter.applyPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
                    formatter = FORMATTER_MILLISECONDS_T;
                } else if (length == 23) {
                    // formatter.applyPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
                    formatter = FORMATTER_MILLISECONDS_T;
                } else if (dateString.endsWith("GMT") || dateString.endsWith("UTC")) {
                    // formatter.applyPattern("EEE, dd MMMM yyyyy HH:mm:ss z");
                    // this has to be done by hand since Joda time can't parse
                    // the timezone
                    // see
                    // http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html
                    dateString = dateString.substring(0, last - 3);
                    formatter = FORMATTER_TIMEZONE;
                }
            }
            DateTimeZone.setDefault(DateTimeZone.UTC);
            DateTime dt = formatter.parseDateTime(dateString);
            return dt.toDate();
        } catch (IllegalArgumentException e) {
            throw new ParseException(e.getLocalizedMessage(), 0);
        }
    }

    public static String formatMillisTZ(Date date) {
        return FORMATTER_MILLISECONDS_T_Z.print(date.getTime());
    }
}