com.funambol.common.pim.utility.TimeUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.funambol.common.pim.utility.TimeUtils.java

Source

/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2005 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */
package com.funambol.common.pim.utility;

import java.sql.Timestamp;
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 java.util.logging.Logger;

import org.joda.time.Duration;
import org.joda.time.Instant;
import org.joda.time.Period;
import org.joda.time.format.ISOPeriodFormat;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;

/**
 * This class contains usefull methods to handle date and time.
 *
 * @version $Id: TimeUtils.java,v 1.9 2008-09-03 09:49:19 mauro Exp $
 */
public class TimeUtils {

    // --------------------------------------------------------------- Constants
    public final static String PATTERN_YYYYMMDD = "yyyyMMdd";
    public final static int PATTERN_YYYYMMDD_LENGTH = 8;

    public final static String PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
    public final static int PATTERN_YYYY_MM_DD_LENGTH = 10;

    public final static String PATTERN_UTC = "yyyyMMdd'T'HHmmss'Z'";
    public final static int PATTERN_UTC_LENGTH = 16;

    // UTC WOZ = UTC without 'Z'
    public final static String PATTERN_UTC_WOZ = "yyyyMMdd'T'HHmmss";
    public final static int PATTERN_UTC_WOZ_LENGTH = 15;

    // UTC WSEP = UTC with separator
    public final static String PATTERN_UTC_WSEP = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    public final static int PATTERN_UTC_WSEP_LENGTH = 20;

    public final static String PATTERN_LOCALTIME = "dd/MM/yyyy HH:mm:ss";
    public final static int PATTERN_LOCALTIME_LENGTH = 19;

    // WOT = without time
    public final static String PATTERN_LOCALTIME_WOT = "dd/MM/yyyy";
    public final static int PATTERN_LOCALTIME_WOT_LENGTH = 10;

    public final static String PATTERN_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public final static int PATTERN_YYYY_MM_DD_HH_MM_SS_LENGTH = 19;

    public final static String PATTERN_EXIF_DATE = "yyyy:MM:dd HH:mm:ss";

    public final static long SECOND_IN_A_DAY = 24 * 60 * 60; //the seconds in a day

    public final static TimeZone TIMEZONE_UTC = TimeZone.getTimeZone("UTC");

    public final static PeriodFormatter INTERVAL_FORMATTER = new PeriodFormatterBuilder().printZeroRarelyLast()
            .appendLiteral("P").appendYears().appendSuffix("Y").appendMonths().appendSuffix("M").appendDays()
            .appendSuffix("D").appendSeparatorIfFieldsAfter("T").appendHours().appendSuffix("H").appendMinutes()
            .appendSuffix("M").appendSeconds().appendSuffix("S").toFormatter();
    /**
     * It's a costant value for the number of minutes in a day
     */
    private static int MINUTES_IN_A_DAY = 60 * 24;

    // ---------------------------------------------------------- Public methods
    /**
     * Converts the given string date from UTC format to Timestamp.
     *
     * @param utcDateTime the string date in UTC format
     * @return a Timestamp object.
     * @throws ParseException if an error occurs during conversion
     */
    public static Timestamp convertUTCToTimestamp(String utcDateTime) throws ParseException {

        if (utcDateTime == null) {
            return null;
        }

        SimpleDateFormat formatter = new SimpleDateFormat(TimeUtils.PATTERN_UTC);
        formatter.setTimeZone(TimeUtils.TIMEZONE_UTC);

        Date date = formatter.parse(utcDateTime);

        return new Timestamp(date.getTime());
    }

    /**
     * Set a string date from UTC format (yyyyMMdd'T'HHmmss'Z') into
     * a format dd/MM/yyyy HH:mm:ss according to default local timezone.
     *
     * @param UTCFormat the input date in UTC format
     * @param logger the logger to use
     * @return actualTime the date into default local timezone
     */
    public static String UTCToLocalTime(String UTCFormat, Logger logger) {

        String actualTime = UTCFormat;
        try {
            SimpleDateFormat formatter = new SimpleDateFormat(PATTERN_UTC);
            formatter.setLenient(false);
            formatter.setTimeZone(TIMEZONE_UTC);
            Date date = formatter.parse(UTCFormat);
            Calendar rightNow = Calendar.getInstance();
            formatter.setCalendar(rightNow);
            formatter.applyPattern(PATTERN_LOCALTIME);
            actualTime = formatter.format(date);

        } catch (Exception e) {
            if (logger != null) {
                logger.severe("Error into convertion from UTC to Local time");
                logger.throwing("TimeUtils", "UTCToLocalTime", e);
            }
        }
        return actualTime;

    }

    /**
     * Gets the day before or after a given argument. Both the argument and the 
     * result are in the "yyyyMMdd" format (the argument can also have dashes).
     * 
     * @param ymd a String representing a date in an all-day format
     * @param after true if the day after is needed, false if it's the day 
     *              before
     * @return a String representing the day before ymd in an all-day
     *         format, or null if ymd was not as expected
     */
    public static String rollOneDay(String ymd, boolean after) {
        String yyyymmdd = ymd.replaceAll("-", "");
        if (yyyymmdd.length() == 8) {
            SimpleDateFormat untimed = new SimpleDateFormat(PATTERN_YYYYMMDD);
            try {
                GregorianCalendar greg = new GregorianCalendar();
                greg.setTime(untimed.parse(yyyymmdd));
                greg.add(GregorianCalendar.DATE, (after ? +1 : -1));
                return untimed.format(greg.getTime());
            } catch (ParseException pe) {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * Set a string date from dd/MM/yyyy HH:mm:ss according to default local
     * timezone into a UTC date pattern yyyyMMdd'T'HHmmss'Z'
     *
     * @param actualTime the date into default local timezone
     * @param logger the logger to use
     * @return UTCFormat the date into UTC format
     */
    public static String localTimeToUTC(String actualTime, Logger logger) {

        String UTCFormat = actualTime;
        try {
            SimpleDateFormat formatter = new SimpleDateFormat(PATTERN_LOCALTIME);

            if (actualTime.length() <= 10) {
                formatter.applyPattern(PATTERN_LOCALTIME_WOT);
            }
            Calendar rightNow = Calendar.getInstance();
            formatter.setCalendar(rightNow);
            formatter.setLenient(false);
            Date date = formatter.parse(actualTime);
            TimeZone tz = TIMEZONE_UTC;
            formatter.setTimeZone(tz);
            formatter.applyPattern(PATTERN_UTC);
            UTCFormat = formatter.format(date);

        } catch (Exception e) {
            if (logger != null) {
                logger.severe("Error into convertion from Local time to UTC");
                logger.throwing("TimeUtils", "localTimeToUTC", e);
            }
        }
        return UTCFormat;
    }

    /**
     * Convert the given date following this roles:
     * <ul>
     * <li>if the given date is in UTC no conversion is required</li>
     * <li>if the given date is not in UTC and the given timezone isn't null,
     * the date is localizated with the timezone and then it's converted in UTC.</li>
     * <li>the returned string is always in UTC</li>
     * <li>if the given timezone is null and the date isn't in UTC, the date is localizated
     * with the default timezone</li>
     * <li>the given date can be in one beetwen the following formats:
     *  <code>yyyyMMdd'T'HHmmss'Z',  yyyyMMdd'T'HHmmss</code></li>
     * </ul>
     * @param sDate the given string date to convert
     * @param timezone TimeZone
     * @return String
     * @throws Exception
     */
    public static String convertLocalDateToUTC(String sDate, TimeZone timezone) throws Exception {

        if (sDate == null || sDate.equals("") || isInAllDayFormat(sDate)) {
            return sDate;
        }

        if (sDate.indexOf('Z') != -1) {
            //
            // No conversion is required
            //
            return sDate;
        }

        DateFormat zFormatter = new SimpleDateFormat(PATTERN_UTC);
        zFormatter.setTimeZone(TIMEZONE_UTC);

        DateFormat noZFormatter = new SimpleDateFormat(PATTERN_UTC_WOZ);

        Date date = null;
        if (timezone != null) {
            noZFormatter.setTimeZone(timezone);
        } else {
            noZFormatter.setTimeZone(TIMEZONE_UTC);
        }
        date = noZFormatter.parse(sDate);

        return zFormatter.format(date);
    }

    /**
     * Convert the given date following this roles:
     * <ul>
     * <li>if the given timezone isn't null,
     * the date is localizated with the timezone and then reformatted in
     * <code>yyyyMMdd'T'HHmmss'Z'</code>.</li>
     * <li>the returned string is always in this format <code>yyyyMMdd'T'HHmmss'Z'</code></li>
     * <li>if the given timezone is null the date is not changed</li>
     * </ul>
     * @param sDate the given string date to convert
     * @param timezone TimeZone
     * @return String
     * @throws Exception
     */
    public static String convertUTCDateToLocal(String sDate, TimeZone timezone) throws Exception {

        if (sDate == null || sDate.equals("") || isInAllDayFormat(sDate)) {
            return sDate;
        }

        if (timezone == null) {
            return sDate;
        }

        if (!sDate.endsWith("Z")) {
            return sDate;
        }

        DateFormat utcFormatter = new SimpleDateFormat(PATTERN_UTC);
        utcFormatter.setTimeZone(TIMEZONE_UTC);

        Date date = null;
        date = utcFormatter.parse(sDate);

        DateFormat utcFormatterWOZ = new SimpleDateFormat(PATTERN_UTC_WOZ);
        utcFormatterWOZ.setTimeZone(timezone);

        return utcFormatterWOZ.format(date);
    }

    /**
     * Convert the given sDate in iso 8601 format.
     * <P>The formats accepted are:
     * <ul>
     * <li>yyyyMMdd'T'HHmmss'Z' (if the date is in this format and the given
     * timezone isn't null and the date doesn't end with 000000Z, the date is localized with
     * the given timezone). We have to check also if the date end with 000000Z because
     * some phones (as Nokia 7650) sends the birthday with the 'Z' but isn't localized</li>
     * <li>yyyy-MM-dd'T'HH:mm:ss'Z' (if the date is in this format and the given
     * timezone isn't null and the date doesn't end with 00:00:00Z, the date is localized with
     * the given timezone).</li>
     * <li>yyyy-MM-dd</li>
     * <li>yyyy/MM/dd</li>
     * <li>yyyyMMdd</li>
     * <li>all formats starts with the previous format (i.e. yyyy-MM-ddTHH:mm:ss.sss)</li>
     * </ul>
     *
     * @param sDate the date
     * @param tz the timezone to apply
     * @return the sDate in iso 8601 format
     */
    public static String normalizeToISO8601(String sDate, TimeZone tz) {

        if (sDate == null || sDate.equals("")) {
            return sDate;
        }

        if (tz != null) {
            //
            // Try to apply the timezone
            //
            SimpleDateFormat utcFormatter = new SimpleDateFormat(PATTERN_UTC);
            utcFormatter.setTimeZone(TIMEZONE_UTC);
            Date date = null;
            try {
                date = utcFormatter.parse(sDate);
                if (!sDate.endsWith("000000Z")) {
                    utcFormatter.setTimeZone(tz);
                    sDate = utcFormatter.format(date);
                }
            } catch (ParseException ex) {
                //
                // Ignore this error. The date isn't in this format.
                //
                // Try with yyyy-MM-dd'T'HH:mm:ss'Z'
                utcFormatter.applyPattern(PATTERN_UTC_WSEP);
                try {
                    date = utcFormatter.parse(sDate);
                    if (!sDate.endsWith("00:00:00Z")) {
                        utcFormatter.setTimeZone(tz);
                        sDate = utcFormatter.format(date);
                    }

                } catch (Exception e) {
                    //
                    // Ignore this error. The date isn't in this format.
                    //
                }
            }
        }
        int year = -1;
        int month = -1;
        int day = -1;
        String tmp = null;
        int last = 0;

        //
        // The first four digits are the year
        //
        tmp = sDate.substring(0, 4);
        year = Integer.parseInt(tmp);

        //
        // Read the month
        //
        char c = sDate.charAt(4);
        if (c == '/' || c == '-') {
            tmp = sDate.substring(5, 7);
            last = 7;
        } else {
            tmp = sDate.substring(4, 6);
            last = 6;
        }
        month = Integer.parseInt(tmp);

        //
        // Read the day
        //
        c = sDate.charAt(last);
        if (c == '/' || c == '-') {
            tmp = sDate.substring(last + 1, last + 3);
        } else {
            tmp = sDate.substring(last, last + 2);
        }
        day = Integer.parseInt(tmp);

        StringBuffer isoDate = new StringBuffer(10);
        isoDate.append(year).append("-");

        if (month < 10) {
            isoDate.append("0");
        }
        isoDate.append(month).append("-");

        if (day < 10) {
            isoDate.append("0");
        }
        isoDate.append(day);
        return isoDate.toString();
    }

    /**
     * Returns the given Iso 8601 duration in minutes
     * @param iso8601Duration String
     * @return int
     */
    public static int getMinutes(String iso8601Duration) {
        if (iso8601Duration == null || iso8601Duration.equals("") || iso8601Duration.equalsIgnoreCase("null")) {
            return -1;
        }

        PeriodFormatter formatter = ISOPeriodFormat.standard();
        Period p = formatter.parsePeriod(iso8601Duration);
        Duration d = p.toDurationFrom(new Instant(0));
        long mills = d.getMillis();
        int minutes = (int) (mills / 60L / 1000L);
        return minutes;
    }

    /**
     * Returns the given minutes in iso 8601 duration format
     * @param minutes String
     * @return String
     */
    public static String getIso8601Duration(String minutes) {

        if (minutes == null || minutes.equals("")) {
            return minutes;
        }

        int min = Integer.parseInt(minutes);

        if (min == -1) {
            return null;
        }

        long mills = min * 60L * 1000L;
        Duration d = new Duration(mills);

        PeriodFormatter formatter = ISOPeriodFormat.standard();
        return formatter.print(d.toPeriod());
    }

    /**
     * If dtStart and duration aren't empty, computes the dtEnd as dtStart + duration
     * and return it. If dtStart or duration are empty, return the given dtEnd unchanges it.
     *
     * The format of the return dtEnd is the same of the dtStart.
     * The format accepted are the following:
     * <lu>
     *  <li>"yyyyMMdd'T'HHmmss'Z'"</li>
     *  <li>"yyyyMMdd'T'HHmmss"</li>
     *  <li>"yyyyMMdd"</li>
     *  <li>"yyyy-MM-dd"</li>
     * </lu>
     *
     * @param dtStart the string contains the start date
     * @param duration the duration of the event
     * @param dtEnd the string contains the end date
     * @param logger the logger to use
     * @return the end date calculated considering the minutes given by duration
     */
    public static String getDTEnd(String dtStart, String duration, String dtEnd, Logger logger) {

        Date dateStart = null;
        SimpleDateFormat format = null;

        if (duration == null || duration.equals("") || duration.equalsIgnoreCase("null") || dtStart == null
                || dtStart.equals("") || dtStart.equalsIgnoreCase("null")) {

            return dtEnd;
        }
        format = new SimpleDateFormat();

        try {
            format.applyPattern(getDateFormat(dtStart));
            dateStart = format.parse(dtStart);
        } catch (ParseException e) {
            logger.severe("Error into dtStart parsing");
            logger.throwing("TimeUtils", "getDTEnd", e);
            //
            // If we are unable to parse dtStart return dtEnd unchanged
            //
            return dtEnd;
        }

        int minutes = getMinutes(duration);

        Calendar calStart = Calendar.getInstance();
        calStart.setTime(dateStart);

        // In order to avoid issues moving on the end date according to the input
        // period using the number of minutes, since strange behaviours were recognized
        // when the day rapresented by the dtEnd was the end of the daylight time,
        // we check if the amount of minutes is enough to perform the addition
        // as the maximum number of days rapresented by minutes more the rest of
        // the division between minutes and the number of minutes in a day.
        if (minutes >= MINUTES_IN_A_DAY) {
            int day = getMinutesAsDay(minutes);
            int remainingMinutes = getRemainingMinutes(minutes);
            calStart.add(Calendar.DATE, day);
            calStart.add(Calendar.MINUTE, remainingMinutes);
        } else {
            calStart.add(Calendar.MINUTE, minutes);
        }

        Date dateEnd = calStart.getTime();

        return format.format(dateEnd);
    }

    /**
     * If dtStart and date into Alarm aren't empty, computes the minutes before
     * to start the reminder as dtStart - date alarm = minutes and return it.
     *
     * The format of the return dtEnd is the same of the dtStart.
     * The format accepted are the following:
     * <lu>
     *  <li>"yyyyMMdd'T'HHmmss'Z'"</li>
     *  <li>"yyyyMMdd'T'HHmmss"</li>
     *  <li>"yyyyMMdd"</li>
     *  <li>"yyyy-MM-dd"</li>
     * </lu>
     * However, all times and dates will be interpreted as UTC.
     *
     * @param dtStart the string contains start date
     * @param dtAlarm String the string contains the alarm
     *
     * @param logger the logger to use
     * @return int minutes before to start reminder
     */
    public static int getAlarmMinutes(String dtStart, String dtAlarm, Logger logger) {
        Date dateStart = null;
        Date dateAlarm = null;

        if (dtStart == null || dtStart.equals("") || dtAlarm == null || dtAlarm.equals("")) {
            return 0;
        }

        try {
            SimpleDateFormat formatter = new SimpleDateFormat();
            formatter.setTimeZone(TIMEZONE_UTC);

            formatter.applyPattern(getDateFormat(dtStart));
            dateStart = formatter.parse(dtStart);

            formatter.applyPattern(getDateFormat(dtAlarm));
            dateAlarm = formatter.parse(dtAlarm);

        } catch (ParseException e) {
            logger.severe("Error during parser date");
            logger.throwing("TimeUtils", "getAlarmMinutes", e);
            //
            // If we are unable to parse dtStart or dtAlarm return 0
            //
            return 0;
        }

        long minutes = dateStart.getTime() - dateAlarm.getTime();

        return (int) (minutes / 1000 / 60);

    }

    /**
     * Calculate the minutes into int format in the case in which the input
     * is into ISO 8601 format; else return the interval
     *
     * @param interval the interval in which the reminder has to be repeated
     *
     * @return int the interval in minutes format
     */
    public static int getAlarmInterval(String interval) {
        if (interval == null) {
            return 0;
        }
        interval = interval.trim();
        if ("".equals(interval)) {
            return 0;
        }

        int sign;
        if (interval.startsWith("-")) {
            interval = interval.substring(1);
            sign = -1;
        } else {
            sign = +1;
        }

        Period period;
        try {
            period = INTERVAL_FORMATTER.parsePeriod(interval);
        } catch (Exception e) {
            return Integer.parseInt(interval.replaceAll("^[0-9]", "")); // best guess
        }

        //@TODO Replace it with new methods in Joda 1.5 when the dependency is
        //      updated to the latest version
        Duration d = period.toDurationFrom(new Instant(0));
        long millis = d.getMillis();
        int minutes = (int) (millis / 60000L);
        return sign * minutes;
    }

    /**
     * Converts a signed number of minutes into an ISO 8601 interval.
     * 
     * @param minutes
     * @return a string like "-PT15M"
     */
    public static String getAlarmInterval(int minutes) {
        if (minutes < 0) {
            return '-' + getAlarmInterval(-minutes);
        }
        Period period = new Period(60000L * minutes);
        return INTERVAL_FORMATTER.print(period);
    }

    /**
     * Check if the date is into format yyyyMMdd or yyyy-MM-dd.
     * If the date is in one of this format then the event is an AllDay event
     *
     * @param date The date to check (Usually this is the start date event)
     * @return boolean true if the format is right, otherwise false
     */
    public static boolean isInAllDayFormat(String date) {
        String pattern = getDateFormat(date);

        if (pattern == null) {
            return false;
        }

        if (pattern.equals(PATTERN_YYYYMMDD) || pattern.equals(PATTERN_YYYY_MM_DD)) {
            return true;
        }
        return false;
    }

    /**
     * Convert date from yyyy-MM-dd format or from yyyyMMdd format into
     * yyyyMMdd'T'HHmmss format.
     *
     * @param stringDate the date to convert
     * @param hhmmss the hours, minutes, seconds to add
     *
     * @return String the date into proper format
     * @throws ParseException if an error occurs during convertion
     */
    public static String convertDateFromInDayFormat(String stringDate, String hhmmss) throws ParseException {

        if (stringDate == null || stringDate.length() == 0) {
            return "";
        }

        StringBuffer sb = null;

        SimpleDateFormat formatter = new SimpleDateFormat(PATTERN_YYYY_MM_DD);
        Date date;
        try {
            formatter.setLenient(false);
            date = formatter.parse(stringDate);
        } catch (ParseException pe) {
            formatter = new SimpleDateFormat(PATTERN_YYYYMMDD);
            formatter.setLenient(false);
            date = formatter.parse(stringDate);
        }
        formatter.applyPattern(PATTERN_YYYYMMDD);
        sb = new StringBuffer(formatter.format(date));
        sb.append('T').append(hhmmss);
        return sb.toString();
    }

    /**
     * Convert date from yyyy-MM-dd or yyyyMMdd format into format yyyyMMdd'T'HHmmss.
     * If inUtc is true the date is converted in yyyyMMdd'T'HHmmss'Z'
     *
     * @param stringDate the date to convert
     * @param hhmmss the hours, minutes, seconds to add
     * @param inUtc true if the format should be the UTC (a 'Z' is added at the
     *              end of the string date), false otherwise
     *
     * @return String the date into proper format
     * @throws ParseException if an error occurs during convertion
     */
    public static String convertDateFromInDayFormat(String stringDate, String hhmmss, boolean inUtc)
            throws ParseException {

        if (stringDate == null || stringDate.length() == 0) {
            return "";
        }

        StringBuffer sb = null;

        String format = getDateFormat(stringDate);
        SimpleDateFormat formatter = null;

        if (format.equals(PATTERN_YYYY_MM_DD)) {
            formatter = new SimpleDateFormat(PATTERN_YYYY_MM_DD);
        } else if (format.equals(PATTERN_YYYYMMDD)) {
            formatter = new SimpleDateFormat(PATTERN_YYYYMMDD);
        } else {
            throw new ParseException("Error, date " + stringDate + " pattern doesn't match the expected ones, "
                    + PATTERN_YYYY_MM_DD + " or " + PATTERN_YYYYMMDD, 0);
        }
        formatter.setLenient(false);
        Date date = formatter.parse(stringDate);
        formatter.applyPattern(PATTERN_YYYYMMDD);
        sb = new StringBuffer(formatter.format(date));
        sb.append('T').append(hhmmss);
        if (inUtc) {
            sb.append('Z');
        }
        return sb.toString();
    }

    /**
     * Convert date from the input date format into specificated format.
     *
     *
     * @param patternToUse the pattern to use
     * @param stringDate the date to convert
     * @return String the date into proper format     
     * @throws ParseException if an error occurs during convertion
     */
    public static String convertDateFromTo(String stringDate, String patternToUse) throws ParseException {
        if (stringDate == null || stringDate.length() == 0) {
            return "";
        }

        String pattern = getDateFormat(stringDate);
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        formatter.setLenient(false);
        Date date = formatter.parse(stringDate);
        formatter.applyPattern(patternToUse);
        return formatter.format(date);
    }

    /**
     * Convert date from the input date format into specificated format.
     * <br>In the conversion the following rules are applied:
     * <ul>
     *     <li>if the given timezoneIn is not null, it is applied on the stringDate
     *         conversion
     *     </li>
     *     <li>if the given timezoneOut is not null, it is applied on the output date
     *     </li>
     * </ul>
     * @param stringDate the date to convert
     * @param patternToUse the required pattern for the output date
     * @param timezoneIn the timezone to apply to the given date
     * @param timezoneOut the timezone to apply on the output date
     * @return String the date into proper format
     * @throws ParseException if an error occurs
     */
    public static String convertDateFromTo(String stringDate, String patternToUse, TimeZone timezoneIn,
            TimeZone timezoneOut) throws ParseException {
        if (stringDate == null || stringDate.length() == 0) {
            return "";
        }

        String pattern = getDateFormat(stringDate);
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        if (timezoneIn != null) {
            formatter.setTimeZone(timezoneIn);

        }
        formatter.setLenient(false);
        Date date = formatter.parse(stringDate);
        formatter.applyPattern(patternToUse);
        if (timezoneOut != null) {
            formatter.setTimeZone(timezoneOut);
        }
        return formatter.format(date);
    }

    /**
     * Convert the given date in the given format.
        
     * @param patternToUse the pattern of the output date
     * @param date the date to convert
     * @return String the date into proper format
     * @throws ParseException if an error occurs
     */
    public static String convertDateTo(Date date, String patternToUse) throws ParseException {
        if (date == null) {
            return null;
        }

        SimpleDateFormat formatter = new SimpleDateFormat();
        formatter.setLenient(false);
        formatter.applyPattern(patternToUse);
        return formatter.format(date);
    }

    /**
     * Convert the given date in the given format.
     *
     *
     * @param timeZone the time zone to use
     * @param patternToUse the pattern of the output date
     * @param date the date to convert
     * @return String the date into proper format     
     * @throws ParseException if an error occurs during convertion
     */
    public static String convertDateTo(Date date, TimeZone timeZone, String patternToUse) throws ParseException {
        if (date == null) {
            return null;
        }

        SimpleDateFormat formatter = new SimpleDateFormat();
        if (timeZone != null) {
            formatter.setTimeZone(timeZone);
        }
        formatter.setLenient(false);
        formatter.applyPattern(patternToUse);
        return formatter.format(date);
    }

    /**
     * Get the date pattern
     *
     * @param date the date to get the format
     * @return String the pattern
     */
    public static String getDateFormat(String date) {

        if (date == null || date.equals("")) {
            return null;
        }

        SimpleDateFormat dateFormat = new SimpleDateFormat();
        String[] patterns = new String[] { PATTERN_UTC, PATTERN_UTC_WOZ, PATTERN_UTC_WSEP, PATTERN_YYYY_MM_DD,
                PATTERN_YYYYMMDD, PATTERN_LOCALTIME, PATTERN_LOCALTIME_WOT, PATTERN_YYYY_MM_DD_HH_MM_SS };

        int[] patternsLength = new int[] { PATTERN_UTC_LENGTH, PATTERN_UTC_WOZ_LENGTH, PATTERN_UTC_WSEP_LENGTH,
                PATTERN_YYYY_MM_DD_LENGTH, PATTERN_YYYYMMDD_LENGTH, PATTERN_LOCALTIME_LENGTH,
                PATTERN_LOCALTIME_WOT_LENGTH, PATTERN_YYYY_MM_DD_HH_MM_SS_LENGTH };

        int s = patterns.length; // and also patternsLength.length
        Date d = null;
        for (int i = 0; i < s; i++) {
            try {
                dateFormat.applyPattern(patterns[i]);
                dateFormat.setLenient(true);
                d = dateFormat.parse(date);

                if (date.length() == patternsLength[i]) {
                    return patterns[i];
                }

            } catch (ParseException e) {
                continue;
            }
        }
        return null;
    }

    /**
     * Checks if the given dates are relative to an all day event.
     * The dates are relative to an all day event if
     * the start date ends with <code>T000000Z</code> and the end date ends with
     * <code>T235959Z</code> or <code>T235900Z</code> or <code>T240000Z</code>
     * @param dateStart String
     * @param dateEnd String
     * @return true if the given dates are relative to an all day event,
     *         false otherwise
     */
    public static boolean isAllDayEvent(String dateStart, String dateEnd) {
        if (dateStart == null || dateEnd == null) {
            return false;
        }

        if (dateStart.endsWith("T000000Z")) {
            if (dateEnd.endsWith("T235959Z") || dateEnd.endsWith("T235900Z") || dateEnd.endsWith("T240000Z")) {
                //
                // It is an all day event.
                //
                return true;
            }
        }
        return false;
    }

    /**
     * Gets the timestamp of the midnight at a given date (i.e., the midnight 
     * at the beginning of that day). The moment corresponds to midnight in UTC.
     * 
     * @param dateTime a date (and, optionally, a time) in the ISO 8601 format
     * @return the timestamp as a long
     * @throws java.text.ParseException if dateTime has a wrong format
     */
    public static long getMidnightTime(String dateTime) throws ParseException {

        while (dateTime.length() < 8) {
            dateTime += "01"; // Quick fix: add default month and/or day
        }
        String yyyyMMdd = dateTime.replaceAll("-", "") // no "yyyy-MM-dd" format
                .substring(0, 8); // gets "yyyyMMdd"

        SimpleDateFormat JUST_DATE = new SimpleDateFormat("yyyyMMdd");
        JUST_DATE.setTimeZone(TimeZone.getTimeZone("UTC"));
        return JUST_DATE.parse(yyyyMMdd).getTime();
    }

    /**
     * Converts the date from its custom format 'fromPattern'
     * (like 'yyyy:MM:dd HH:mm:ss') applying the 'toPattern' format.
     *
     * @param stringDate the date to convert
     * @param fromPattern the actual date pattern
     * @param toPattern the pattern to apply at the date
     * @return String the date in the 'toPattern'
     * @throws ParseException if an error occurs during convertion
     */
    public static String convertDateFromTo(String stringDate, String fromPattern, String toPattern)
            throws ParseException {

        if (stringDate == null || stringDate.length() == 0) {
            return "";
        }

        SimpleDateFormat formatter = new SimpleDateFormat(fromPattern);
        Date date = formatter.parse(stringDate);
        return new SimpleDateFormat(toPattern).format(date);
    }

    // --------------------------------------------------------- Private methods
    /**
     * Allows to translate the given number of minutes in
     * the greatest number of day contained in the time rapresent
     * by minutes
     * 
     * @param minutes is the number of minutes we want to traslate in the number
     * of days
     * 
     * @return the greatest number of days contained in the given
     * time expressed by minutes
     */
    private static int getMinutesAsDay(int minutes) {
        int result = 0;
        if (minutes >= MINUTES_IN_A_DAY) {
            result = minutes / MINUTES_IN_A_DAY;
        }
        return result;

    }

    /**
     * return the module between the given number of minutes
     * and the number of minutes in a day
     *
     * @param minutes the number of minutes we want to consider
     *
     * @return the rest you obtain dividing the input values for the number
     * of minutes in a day
     */
    private static int getRemainingMinutes(int minutes) {
        return minutes % MINUTES_IN_A_DAY;
    }
}