at.gv.egovernment.moa.util.DateTimeUtils.java Source code

Java tutorial

Introduction

Here is the source code for at.gv.egovernment.moa.util.DateTimeUtils.java

Source

/*
 * Copyright 2003 Federal Chancellery Austria
 * MOA-ID has been developed in a cooperation between BRZ, the Federal
 * Chancellery Austria - ICT staff unit, and Graz University of Technology.
 *
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
 * the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * http://www.osor.eu/eupl/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 *
 * This product combines work with different licenses. See the "NOTICE" text
 * file for details on the various modules and licenses.
 * The "NOTICE" text file is part of the distribution. Any derivative works
 * that you distribute must include a readable copy of the "NOTICE" text file.
 */

package at.gv.egovernment.moa.util;

import java.io.StringWriter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

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

/**
 * Utility for parsing and building XML type <code>dateTime</code>,
 * according to ISO 8601.
 * 
 * @author Patrick Peck
 * @version $Id$
 * @see <code>http://www.w3.org/2001/XMLSchema-datatypes"</code>
 */
public class DateTimeUtils {
    /** Error messages. */
    private static MessageProvider msg = MessageProvider.getInstance();

    //  /**
    //   * Builds a <code>dateTime</code> value from a <code>Calendar</code> value.
    //   * @param cal the <code>Calendar</code> value
    //   * @return the <code>dateTime</code> value
    //   */
    //  public static String buildDateTime(Calendar cal, boolean useUTC) {
    //     
    //     if (useUTC)
    //        return buildDateTimeUTC(cal);
    //     else {
    //       StringWriter out = new StringWriter();
    //       out.write("" + cal.get(Calendar.YEAR));
    //       out.write("-");
    //       out.write(to2DigitString(cal.get(Calendar.MONTH) + 1));
    //       out.write("-");
    //       out.write(to2DigitString(cal.get(Calendar.DAY_OF_MONTH)));
    //       out.write("T");
    //       out.write(to2DigitString(cal.get(Calendar.HOUR_OF_DAY)));
    //       out.write(":");
    //       out.write(to2DigitString(cal.get(Calendar.MINUTE)));
    //       out.write(":");
    //       out.write(to2DigitString(cal.get(Calendar.SECOND)));
    //       int tzOffsetMilliseconds =
    //         cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
    //       if (tzOffsetMilliseconds != 0) {
    //         int tzOffsetMinutes = tzOffsetMilliseconds / (1000 * 60);
    //         int tzOffsetHours = tzOffsetMinutes / 60;
    //         tzOffsetMinutes -= tzOffsetHours * 60;
    //         if (tzOffsetMilliseconds > 0) {
    //           out.write("+");
    //           out.write(to2DigitString(tzOffsetHours));
    //           out.write(":");
    //           out.write(to2DigitString(tzOffsetMinutes));
    //         } else {
    //           out.write("-");
    //           out.write(to2DigitString(-tzOffsetHours));
    //           out.write(":");
    //           out.write(to2DigitString(-tzOffsetMinutes));
    //         }
    //       }
    //       return out.toString();
    //     }
    //  }

    /**
     * Builds a <code>dateTime</code> value in UTC from a <code>Calendar</code> value.
     * @param cal the <code>Calendar</code> value
     * @return the <code>dateTime</code> value
     */
    public static String buildDateTimeUTC(Calendar cal) {

        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        f.setTimeZone(TimeZone.getTimeZone("UTC"));

        return f.format(cal.getTime());
    }

    /**
     * Builds a <code>dateTime</code> value in UTC from a <code>Calendar</code> value.
     * @param cal the <code>Calendar</code> value
     * @return the <code>dateTime</code> value
     */
    public static String buildDateTimeUTC(Date cal) {

        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        f.setTimeZone(TimeZone.getTimeZone("UTC"));

        return f.format(cal);

    }

    /**
     * Builds a <code>dateTime</code> value from a <code>Calendar</code> value.
     * @param cal the <code>Calendar</code> value
     * @return the <code>dateTime</code> value
     */
    public static String buildDate(Calendar cal) {
        StringWriter out = new StringWriter();
        out.write("" + cal.get(Calendar.YEAR));
        out.write("-");
        out.write(to2DigitString(cal.get(Calendar.MONTH) + 1));
        out.write("-");
        out.write(to2DigitString(cal.get(Calendar.DAY_OF_MONTH)));
        return out.toString();
    }

    /**
     * Builds a <code>dateTime</code> value from a <code>Calendar</code> value.
     * @param cal the <code>Calendar</code> value
     * @return the <code>dateTime</code> value
     */
    public static String buildTime(Calendar cal) {
        StringWriter out = new StringWriter();
        out.write(to2DigitString(cal.get(Calendar.HOUR_OF_DAY)));
        out.write(":");
        out.write(to2DigitString(cal.get(Calendar.MINUTE)));
        out.write(":");
        out.write(to2DigitString(cal.get(Calendar.SECOND)));

        return out.toString();
    }

    /**
     * Converts month, day, hour, minute, or second value
     * to a 2 digit String.
     * @param number the month, day, hour, minute, or second value
     * @return 2 digit String
     */
    private static String to2DigitString(int number) {
        if (number < 10)
            return "0" + number;
        else
            return "" + number;
    }

    /**
     * Parse a <code>String</code> containing a date and time instant, given in
     * ISO 8601 format.
     * 
     * @param dateTime The <code>String</code> to parse.
     * @return The <code>Date</code> representation of the contents of
     * <code>dateTime</code>.
     * @throws ParseException Parsing the <code>dateTime</code> failed.
     */
    public static Date parseDateTime(String dateTime) throws ParseException {
        GregorianCalendar calendar;
        long time;
        int yearSign = 1, year, month, day;
        int hour, minute, second;
        double fraction = 0.0;
        int tzSign = 1, tzHour = 0, tzMinute = 0;
        int curPos = 0;
        String fractStr;
        boolean localTime = false;
        char c;

        // parse year sign
        ensureChars(dateTime, curPos, 1);
        c = dateTime.charAt(curPos);
        if (c == '+' || c == '-') {
            yearSign = c == '+' ? 1 : -1;
            curPos++;
        }

        // parse year
        year = parseInt(dateTime, curPos, 4);
        curPos += 4;

        // parse '-'
        ensureChar(dateTime, curPos, '-');
        curPos++;

        // parse month
        month = parseInt(dateTime, curPos, 2);
        ensureValue(month, 1, 12, curPos);
        curPos += 2;

        // parse '-'
        ensureChar(dateTime, curPos, '-');
        curPos++;

        // parse day
        day = parseInt(dateTime, curPos, 2);
        ensureValue(day, 1, 31, curPos);
        curPos += 2;

        // parse 'T'
        ensureChar(dateTime, curPos, 'T');
        curPos++;

        // parse hour
        hour = parseInt(dateTime, curPos, 2);
        ensureValue(hour, 0, 23, curPos);
        curPos += 2;

        // parse ':'
        ensureChar(dateTime, curPos, ':');
        curPos++;

        // parse minute
        minute = parseInt(dateTime, curPos, 2);
        ensureValue(minute, 0, 59, curPos);
        curPos += 2;

        // parse ':'
        ensureChar(dateTime, curPos, ':');
        curPos++;

        // parse second
        second = parseInt(dateTime, curPos, 2);
        ensureValue(second, 0, 59, curPos);
        curPos += 2;

        // parse a fraction
        if (dateTime.length() > curPos && dateTime.charAt(curPos) == '.') {
            curPos++;
            ensureDigits(dateTime, curPos, 1);
            fractStr = "0.";
            fractStr += dateTime.substring(curPos, curPos + countDigits(dateTime, curPos));
            fraction = Double.parseDouble(fractStr);
            curPos += countDigits(dateTime, curPos);
        }

        // parse a time zone
        if (dateTime.length() > curPos) {
            c = dateTime.charAt(curPos);
            if (c == 'Z') {
                curPos++;
            } else if (c == '+' || c == '-') {
                // parse time zone sign
                tzSign = c == '+' ? 1 : -1;
                curPos++;

                // parse time zone hour
                tzHour = parseInt(dateTime, curPos, 2);
                ensureValue(tzHour, 0, 14, curPos);
                curPos += 2;

                // parse ':'
                ensureChar(dateTime, curPos, ':');
                curPos++;

                // parse time zone minute
                tzMinute = parseInt(dateTime, curPos, 2);
                ensureValue(tzMinute, 0, 59, curPos);
                curPos += 2;
            }
        } else {
            localTime = true;
        }

        // if we have characters left, it's an error
        if (dateTime.length() != curPos) {
            throw new ParseException(msg.getMessage("datetime.00", null), curPos);
        }

        // build the Date object
        year = year * yearSign;
        try {
            calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
            calendar.set(year, month - 1, day, hour, minute, second);
            calendar.set(Calendar.MILLISECOND, 0);
            time = calendar.getTime().getTime();
            time += (long) (fraction * 1000.0);
            time -= tzSign * ((tzHour * 60) + tzMinute) * 60 * 1000;
            if (localTime) {
                time -= TimeZone.getDefault().getRawOffset();
            }
            return new Date(time);
        } catch (IllegalArgumentException e) {
            throw new ParseException(msg.getMessage("datetime.00", null), curPos);
        }

    }

    /**
     * Parse an integer value.
     * 
     * @param str The <code>String</code> containing the digits.
     * @param curPos The starting position.
     * @param digits The number of digist making up the integer value.
     * @return int The integer representation of the digits contained in
     * <code>str</code>.
     * @throws ParseException Parsing the integer value failed.
     */
    private static int parseInt(String str, int curPos, int digits) throws ParseException {

        ensureDigits(str, curPos, digits);
        return Integer.parseInt(str.substring(curPos, curPos + digits));
    }

    /**
     * Count the number of digits following <code>curPos</code>.
     * 
     * @param str The <code>String</code> in which to count digits.
     * @param curPos The starting position.
     * @return int The number of digits.
     */
    private static int countDigits(String str, int curPos) {
        int i;

        for (i = curPos; i < str.length() && Character.isDigit(str.charAt(i)); i++)
            ;
        return i - curPos;
    }

    /**
     * Ensure that a value falls in a given min/max range.
     * 
     * @param value The value to check.
     * @param min The minimum allowed value.
     * @param max The maximum allowed value.
     * @param curPos To indicate the parsing position in the
     * <code>ParseException</code>.
     * @throws ParseException Thrown, if <code>value &lt; min || value &gt;
     * max</code>
     */
    private static void ensureValue(int value, int min, int max, int curPos) throws ParseException {

        if (value < min || value > max) {
            throw new ParseException(msg.getMessage("datetime.00", null), curPos);
        }
    }

    /**
     * Ensure that the given <code>String</code> has a number of characters left.
     * 
     * @param str The <code>String</code> to check for its length.
     * @param curPos The starting position.
     * @param count The minimum number of characters that <code>str</code> must
     * contain, starting at from <code>curPos</code>.
     * @throws ParseException Thrown, if 
     * <code>curPos + count &gt; str.length()</code>.
     */
    private static void ensureChars(String str, int curPos, int count) throws ParseException {
        if (curPos + count > str.length()) {
            throw new ParseException(msg.getMessage("datetime.00", null), curPos);
        }
    }

    /**
     * Ensure that a given <code>String</code> contains a certain character at a
     * certain position.
     * 
     * @param str The <code>String</code> in which to look up the character. 
     * @param curPos The position in <code>str</code> that must contain the
     * character.
     * @param c The character value that must be contained at position
     * <code>curPos</code>.
     * @throws ParseException Thrown, if the characters do not match or
     * <code>curPos</code> is out of range.
     */
    private static void ensureChar(String str, int curPos, char c) throws ParseException {

        ensureChars(str, curPos, 1);
        if (str.charAt(curPos) != c) {
            throw new ParseException(msg.getMessage("datetime.00", null), curPos);
        }
    }

    /**
     * Ensure that a given <code>String</code> contains a number of digits,
     * starting at a given position.
     * 
     * @param str The <code>String</code> to scan for digits. 
     * @param curPos The starting postion.
     * @param count The number of digits that must be contained in
     * <code>str</code>, starting at <code>curPos</code>.
     * @throws ParseException Thrown, if <code>str</code> is not long enough, or
     * one of the characters following <code>curPos</code> in <code>str</code> is
     * not a digit.
     */
    private static void ensureDigits(String str, int curPos, int count) throws ParseException {

        ensureChars(str, curPos, count);
        for (int i = curPos; i < curPos + count; i++) {
            if (!Character.isDigit(str.charAt(i))) {
                throw new ParseException(msg.getMessage("datetime.00", null), curPos);
            }
        }
    }

    /**
     * Calculates the age if date of birth is given (for a calendar time stamp)
     * @param dateOfBirth Date of Birth
     * @param now Calendar time stamp at which the age needs to be calculated for
     * @return Age of a person
     */
    public static int calcAge(Calendar dateOfBirth, Calendar now) {
        int age = now.get(Calendar.YEAR) - dateOfBirth.get(Calendar.YEAR);

        int nowM = now.get(Calendar.MONTH);
        int dobM = dateOfBirth.get(Calendar.MONTH);
        int nowDOM = now.get(Calendar.DAY_OF_MONTH);
        int dobDOM = dateOfBirth.get(Calendar.DAY_OF_MONTH);

        if ((nowM < dobM) || ((nowM == dobM) && (nowDOM < dobDOM))) {
            age--;
        }

        if (age < 0) {
            throw new IllegalArgumentException("Calculated age results in negative value.");
        }
        return age;
    }

    /**
     * Calculates the age if date of birth is given as Calendar object
     * @param dateOfBirth Date of Birth as Calendar object
     * @return Age of a person
     */
    public static int calcAge(Calendar dateOfBirth) {
        return calcAge(dateOfBirth, Calendar.getInstance());
    }

    /**
     * Calculates the age if date of birth is given (for a date time stamp)
     * @param dateOfBirth Date of Birth
     * @param now Date time stamp at which the age needs to be calculated for
     * @return Age of a person
     */
    public static int calcAge(Date dateOfBirth, Date now) {
        Calendar dob = Calendar.getInstance();
        dob.setTime(dateOfBirth);
        Calendar nowCal = Calendar.getInstance();
        nowCal.setTime(now);
        return calcAge(dob, nowCal);
    }

    /**
     * Calculates the age if date of birth is given as Date object
     * @param dateOfBirth Date of Birth as Date object
     * @return Age of a person
     */
    public static int calcAge(Date dateOfBirth) {
        return calcAge(dateOfBirth, new Date());
    }

    public static String formatPEPSDateToMOADate(String pepsDate) {

        if (StringUtils.isEmpty(pepsDate)) {
            return null;
        }

        DateTimeFormatter fmt = null;

        switch (pepsDate.length()) {
        case 4:
            fmt = DateTimeFormat.forPattern("yyyy");
            break;
        case 6:
            fmt = DateTimeFormat.forPattern("yyyyMM");
            break;
        case 8:
            fmt = DateTimeFormat.forPattern("yyyyMMdd");
            break;
        default:
            fmt = DateTimeFormat.forPattern("yyyy-MM-dd");
            break;
        }

        DateTime dt = fmt.parseDateTime(pepsDate);
        DateTimeFormatter fmt2 = DateTimeFormat.forPattern("yyyy-MM-dd");
        return fmt2.print(dt);

    }

    /**
     * Returns a date as String using a provided format
     * @param format Format the date/time should be returned
     * @return Date/Time as String formatted according the provided format
     */
    public static String getDateTimeWithFormat(String format) {
        DateFormat dateFormat = new SimpleDateFormat(format);
        Date date = new Date();
        return dateFormat.format(date);
    }

}