app.rappla.calendar.Date.java Source code

Java tutorial

Introduction

Here is the source code for app.rappla.calendar.Date.java

Source

/*
 * Copyright (C) 2005-2006 Craig Knudsen and other authors
 * (see AUTHORS for a complete list)
 *
 * JavaCalTools is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of the
 * License, or (at your option) any later version.
 *
 * 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 Lesser General Public
 * License for more details.
 * 
 * A copy of the GNU Lesser General Public License is included in the Wine
 * distribution in the file COPYING.LIB. If you did not receive this copy,
 * write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA.
 */

package app.rappla.calendar;

import java.util.Calendar;
import java.util.Locale;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

/**
 * Base class for use with a variety of date-related iCalendar fields including
 * LAST-MODIFIED, DTSTAMP, DTSTART, etc. This can represent both a date and a
 * date-time.
 * 
 * @version $Id: Date.java,v 1.22 2007/05/17 11:21:20 cknudsen Exp $
 * @author Craig Knudsen, craig@k5n.us
 */
public class Date extends Property implements Constants, Comparable<Date> {
    int year, month, day;
    int hour, minute, second;
    // Code below by Jeremy
    int ehour, eminute, esecond;
    String dateType;
    // Code above by Jeremy
    boolean isUTC = false;
    boolean dateOnly = false; // is date only (rather than date-time)?
    // Code below edited by Amos
    public static int[] monthDays = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

    public static int[] leapMonthDays = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    // Code above edited by Amos
    String tzid = null;
    public static final int SUNDAY = 0;
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;

    /**
     * Constructor: create a date based on the specified year, month and day.
     * 
     * @param dateType
     *            Type of date; this should be an ical property name like
     *            DTSTART, DTEND or DTSTAMP.
     * @param year
     *            The 4-digit year
     * @param month
     *            The month (1-12)
     * @param day
     *            The day of the month (1-31)
     */

    public Date(String dateType, int year, int month, int day) throws BogusDataException {
        super(dateType, "");

        this.year = year;
        this.month = month;
        this.day = day;
        this.hour = this.minute = this.second = 0;
        this.dateOnly = true;

        String yearStr, monthStr, dayStr;

        yearStr = "" + year;
        monthStr = "" + month;
        dayStr = "" + day;
        while (yearStr.length() < 4)
            yearStr = '0' + yearStr;
        if (monthStr.length() < 2)
            monthStr = '0' + monthStr;
        if (dayStr.length() < 2)
            dayStr = '0' + dayStr;
        value = yearStr + monthStr + dayStr;

        // Add attribute that says date-only
        addAttribute("VALUE", "DATE");
    }

    /**
     * Constructor: create a date based on the specified year, month and day.
     * 
     * @param dateType
     *            Type of date; this should be an ical property name like
     *            DTSTART, DTEND or DTSTAMP.
     * @param year
     *            The 4-digit year
     * @param month
     *            The month (1-12)
     * @param day
     *            The day of the month (1-31)
     * @param hour
     *            The hour of day (0-23)
     * @param min
     *            minute of hour (0-59(
     * @param sec
     *            seconds (0-59)
     */

    public Date(String dateType, int year, int month, int day, int hour, int min, int sec)
            throws BogusDataException {
        super(dateType, "");
        // code below by Jeremy//
        this.dateType = dateType;
        // code above by Jeremy//
        this.year = year;
        this.month = month;
        this.day = day;
        this.hour = hour;
        this.minute = min;
        this.second = sec;
        this.dateOnly = false;

        String yearStr, monthStr, dayStr, hourStr, minStr, secStr;

        yearStr = "" + year;
        monthStr = "" + month;
        dayStr = "" + day;
        hourStr = "" + hour;
        minStr = "" + min;
        secStr = "" + sec;

        while (yearStr.length() < 4)
            yearStr = '0' + yearStr;
        if (monthStr.length() < 2)
            monthStr = '0' + monthStr;
        if (dayStr.length() < 2)
            dayStr = '0' + dayStr;
        if (hourStr.length() < 2)
            hourStr = '0' + hourStr;
        if (minStr.length() < 2)
            minStr = '0' + minStr;
        if (secStr.length() < 2)
            secStr = '0' + secStr;

        // TODO: use StringBuffer to speed this up
        // TODO: validate values
        value = yearStr + monthStr + dayStr + 'T' + hourStr + minStr + secStr;

        // Add attribute that says date has a time
        addAttribute("VALUE", "DATE-TIME");
    }

    // Code below by Jeremy
    public Date(String dateType, int year, int month, int day, int hour, int min, int sec, int ehour, int emin,
            int esec) throws BogusDataException {
        super(dateType, "");

        this.dateType = dateType;
        this.year = year;
        this.month = month;
        this.day = day;
        this.hour = hour;
        this.minute = min;
        this.second = sec;
        this.ehour = ehour;
        this.eminute = emin;
        this.esecond = esec;
        this.dateOnly = false;

        String yearStr, monthStr, dayStr, hourStr, minStr, secStr, ehourStr, eminStr, esecStr;

        yearStr = "" + year;
        monthStr = "" + month;
        dayStr = "" + day;
        hourStr = "" + hour;
        minStr = "" + min;
        secStr = "" + sec;
        ehourStr = "" + ehour;
        eminStr = "" + emin;
        esecStr = "" + esec;

        while (yearStr.length() < 4)
            yearStr = '0' + yearStr;
        if (monthStr.length() < 2)
            monthStr = '0' + monthStr;
        if (dayStr.length() < 2)
            dayStr = '0' + dayStr;
        if (hourStr.length() < 2)
            hourStr = '0' + hourStr;
        if (minStr.length() < 2)
            minStr = '0' + minStr;
        if (secStr.length() < 2)
            secStr = '0' + secStr;
        if (ehourStr.length() < 2)
            ehourStr = '0' + ehourStr;
        if (eminStr.length() < 2)
            eminStr = '0' + eminStr;
        if (esecStr.length() < 2)
            esecStr = '0' + esecStr;

        // TODO: use StringBuffer to speed this up
        // TODO: validate values
        value = yearStr + monthStr + dayStr + 'T' + hourStr + minStr + secStr + ehourStr + eminStr + esecStr;

        // Add attribute that says date has a time
        addAttribute("VALUE", "DATE-TIME");
    }

    // code above by Jeremy

    /**
     * Constructor
     * 
     * @param icalStr
     *            One or more lines of iCalendar that specifies a date
     * @param parseMode
     *            PARSE_STRICT or PARSE_LOOSE
     */
    public Date(String icalStr) throws ParseException, BogusDataException {
        super(icalStr);

        year = month = day = 0;
        hour = minute = second = 0;

        for (int i = 0; i < attributeList.size(); i++) {
            Attribute a = attributeAt(i);
            String aname = a.name.toUpperCase(Locale.ENGLISH);
            String aval = a.value.toUpperCase(Locale.ENGLISH);
            // TODO: not sure if any attributes are allowed here...
            // Look for VALUE=DATE or VALUE=DATE-TIME
            // DATE means untimed for the event
            if (aname.equals("VALUE")) {
                if (aval.equals("DATE")) {
                    dateOnly = true;
                } else if (aval.equals("DATE-TIME")) {
                    dateOnly = false;
                }
            } else if (aname.equals("TZID")) {
                tzid = a.value;
            } else {
                // TODO: anything else allowed here?
            }
        }

        String inDate = value;

        if (inDate.length() < 8) {
            // Invalid format
            throw new ParseException("Invalid date format '" + inDate + "'", inDate);
        }

        // Make sure all parts of the year are numeric.
        for (int i = 0; i < 8; i++) {
            char ch = inDate.charAt(i);
            if (ch < '0' || ch > '9') {
                throw new ParseException("Invalid date format '" + inDate + "'", inDate);
            }
        }
        year = Integer.parseInt(inDate.substring(0, 4));
        month = Integer.parseInt(inDate.substring(4, 6));
        day = Integer.parseInt(inDate.substring(6, 8));
        if (day < 1 || day > 31 || month < 1 || month > 12)
            throw new BogusDataException("Invalid date '" + inDate + "'", inDate);
        // Make sure day of month is valid for specified month
        if (year % 4 == 0) {
            // leap year
            if (day > leapMonthDays[month - 1]) {
                throw new BogusDataException("Invalid day of month '" + inDate + "'", inDate);
            }
        } else {
            if (day > monthDays[month - 1]) {
                throw new BogusDataException("Invalid day of month '" + inDate + "'", inDate);
            }
        }
        // TODO: parse time, handle localtime, handle timezone
        if (inDate.length() > 8) {
            // TODO make sure dateOnly == false
            if (inDate.charAt(8) == 'T') {
                try {
                    hour = Integer.parseInt(inDate.substring(9, 11));
                    minute = Integer.parseInt(inDate.substring(11, 13));
                    second = Integer.parseInt(inDate.substring(13, 15));
                    if (hour > 23 || minute > 59 || second > 59) {
                        throw new BogusDataException("Invalid time in date string '" + inDate + "'", inDate);
                    }
                    if (inDate.length() > 15) {
                        isUTC = inDate.charAt(15) == 'Z';
                    }
                } catch (NumberFormatException nef) {
                    throw new BogusDataException("Invalid time in date string '" + inDate + "' - " + nef, inDate);
                }
            } else {
                // Invalid format
                throw new ParseException("Invalid date format '" + inDate + "'", inDate);
            }
        } else {
            // Just date, no time
            dateOnly = true;
        }

        if (isUTC && !dateOnly) {
            // Use Joda Time to convert UTC to localtime
            DateTime utcDateTime = new DateTime(DateTimeZone.UTC);
            utcDateTime = utcDateTime.withDate(year, month, day).withTime(hour, minute, second, 0);
            DateTime localDateTime = utcDateTime.withZone(DateTimeZone.getDefault());
            year = localDateTime.getYear();
            month = localDateTime.getMonthOfYear();
            day = localDateTime.getDayOfMonth();
            hour = localDateTime.getHourOfDay();
            minute = localDateTime.getMinuteOfHour();
            second = localDateTime.getSecondOfMinute();
        } else if (tzid != null) {
            DateTimeZone tz = DateTimeZone.forID(tzid);
            if (tz != null) {
                // Convert to localtime
                DateTime utcDateTime = new DateTime(tz);
                utcDateTime = utcDateTime.withDate(year, month, day).withTime(hour, minute, second, 0);
                DateTime localDateTime = utcDateTime.withZone(DateTimeZone.getDefault());
                year = localDateTime.getYear();
                month = localDateTime.getMonthOfYear();
                day = localDateTime.getDayOfMonth();
                hour = localDateTime.getHourOfDay();
                minute = localDateTime.getMinuteOfHour();
                second = localDateTime.getSecondOfMinute();
                // Since we have converted to localtime, remove the TZID
                // attribute
                this.removeNamedAttribute("TZID");
            }
        }
        isUTC = false;

        // Add attribute that says date-only or date with time
        if (dateOnly)
            addAttribute("VALUE", "DATE");
        else
            addAttribute("VALUE", "DATE-TIME");

    }

    /**
     * Get a Data object that represents the current date and has no time
     * information.
     * 
     * @param dateType
     *            Type of date; this should be an ical property name like
     *            DTSTART, DTEND or DTSTAMP.
     * @return A Date object set to the current date
     */
    public static Date getCurrentDate(String dateType) {
        Date d = null;
        Calendar c = Calendar.getInstance();
        try {
            d = new Date(dateType, c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DAY_OF_MONTH));
        } catch (BogusDataException e2) {
            // This should never happen since we're setting the m/d/y
            System.err.println(e2.toString());
            e2.printStackTrace();
        }
        return d;
    }

    /**
     * Get a Data object that represents the current date and time information.
     * 
     * @param dateType
     *            Type of date; this should be an ical property name like
     *            DTSTART, DTEND or DTSTAMP.
     * @return A Date object set to the current date
     */
    public static Date getCurrentDateTime(String dateType) {
        Date d = null;
        Calendar c = Calendar.getInstance();
        try {
            d = new Date(dateType, c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DAY_OF_MONTH));
            d.setHour(c.get(Calendar.HOUR_OF_DAY));
            d.setMinute(c.get(Calendar.MINUTE));
            d.setSecond(c.get(Calendar.SECOND));
            d.setDateOnly(false);
        } catch (BogusDataException e2) {
            // This should never happen since we're setting the m/d/y
            System.err.println(e2.toString());
            e2.printStackTrace();
        }
        return d;
    }

    public Calendar toCalendar() {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month - 1);
        c.set(Calendar.DAY_OF_MONTH, day);
        c.set(Calendar.HOUR_OF_DAY, hour);
        c.set(Calendar.MINUTE, minute);
        c.set(Calendar.SECOND, second);
        return c;
    }

    public boolean isDateOnly() {
        return dateOnly;
    }

    public void setDateOnly(boolean dateOnly) {
        this.dateOnly = dateOnly;
        this.addAttribute("VALUE", dateOnly ? "DATE" : "DATE-TIME");
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public int getHour() {
        return hour;
    }

    public void setHour(int hour) {
        this.hour = hour;
    }

    public int getMinute() {
        return minute;
    }

    public void setMinute(int minute) {
        this.minute = minute;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getSecond() {
        return second;
    }

    public void setSecond(int second) {
        this.second = second;
    }

    public int getEHour() {
        return ehour;
    }

    // code below by Jeremy//
    public void setEHour(int ehour) {
        this.ehour = ehour;
    }

    public int getEMinute() {
        return eminute;
    }

    public void setEMinute(int eminute) {
        this.eminute = eminute;
    }

    public int getYear() {
        return year;
    }

    public int getESecond() {
        return esecond;
    }

    public void setESecond(int esecond) {
        this.esecond = esecond;
    }

    public String getDateType() {
        return dateType;
    }

    // Code above by Jeremy//

    public void setYear(int year) {
        this.year = year;
    }

    /**
     * Get the day of the week where 0=Sunday, 1=Monday, etc.
     * 
     * @return
     */
    public int getDayOfWeek() {
        return Utils.getDayOfWeek(year, month, day);
    }

    public int getDayOfYear() {
        int[] days = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        int[] ldays = { -1, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

        int ret = 0;
        for (int i = 1; i < this.month; i++) {
            ret += (this.year % 4 == 0 ? ldays[i] : days[i]);
        }
        ret += this.day;
        return ret;
    }

    /**
     * Get the ISO8601 week of year. NOTE: This is DIFFERENT than the
     * java.util.Calendar week number.
     * 
     * @return
     */
    public int getWeekOfYear() {
        int weekdayJan1 = Utils.getFirstDayOfWeekForYear(this.year);
        int[] offsetsToWeek0 = { 6, 7, 8, 9, 10, 4, 5 };
        int offsetToWeek0 = offsetsToWeek0[weekdayJan1];
        int thisDoy = this.getDayOfYear();
        int daysSinceStartOfWeek0 = thisDoy + offsetToWeek0;
        int weekNum = daysSinceStartOfWeek0 / 7;
        return weekNum;
    }

    /**
     * Get the number of days in the current month.
     * 
     * @return
     */
    public int getDaysInMonth() {
        if (this.year % 4 == 0)
            return Date.leapMonthDays[this.month - 1];
        else
            return monthDays[this.month - 1];
    }

    public boolean equals(Object o) {
        if (o instanceof Date) {
            return (this.compareTo((Date) o) == 0);
        } else {
            return false;
        }
    }

    public Date clone(boolean dateOnly) {
        Date ret = null;
        try {
            if (dateOnly)
                ret = new Date(this.name, this.year, this.month, this.day);
            else
                ret = new Date(this.name, this.year, this.month, this.day, this.hour, this.minute, this.second);
        } catch (BogusDataException e1) {
            // TODO
        }
        for (int i = 0; i < this.attributeList.size(); i++) {
            Attribute a = this.attributeAt(i);
            ret.addAttribute(a.name, a.value);
        }
        return ret;
    }

    public Date clone() {
        return clone(this.dateOnly);
    }

    /**
     * Is the date/time before the specified date?
     * 
     * @param d2
     *            The Date object to compare against
     * @return
     */
    public boolean isBefore(Date d2) {
        int ret = this.compareTo(d2);
        return ret < 0;
    }

    /**
     * Is the date/time after the specified date?
     * 
     * @param d2
     *            The Date object to compare against
     * @return
     */
    public boolean isAfter(Date d2) {
        int ret = this.compareTo(d2);
        return ret > 0;
    }

    public int compareTo(Date anotherDate) {
        Date d2 = (Date) anotherDate;
        if (this.year < d2.year)
            return -1;
        if (this.year > d2.year)
            return 1;
        if (this.month < d2.month)
            return -1;
        if (this.month > d2.month)
            return 1;
        if (this.day < d2.day)
            return -1;
        if (this.day > d2.day)
            return 1;
        if (this.dateOnly && d2.dateOnly)
            return 0;
        if (!this.dateOnly && d2.dateOnly)
            return -1;
        if (this.dateOnly && !d2.dateOnly)
            return -1;
        if (this.hour < d2.hour)
            return -1;
        if (this.hour > d2.hour)
            return 1;
        if (this.minute < d2.minute)
            return -1;
        if (this.minute > d2.minute)
            return 1;
        if (this.second < d2.second)
            return -1;
        if (this.second > d2.second)
            return 1;
        return 0;

    }

    @Override
    public int hashCode() {
        // return this Date's total seconds as hash code (disregarding any leap
        // days)
        long hash = year * 32140800;
        hash += month * 2678400;
        hash += day * 86400;
        if (!dateOnly) {
            hash += hour * 3600;
            hash += minute * 60;
            hash += second;
        }
        return (int) hash;
    }

    @Override
    public String toString() {
        if (dateOnly)
            return String.format(Locale.ENGLISH, "%02d.%02d.%04d", day, month, year);
        else
            return String.format(Locale.ENGLISH, "%02d.%02d.%04d %02d:%02d:%02d", day, month, year, hour, minute,
                    second);
    }

}