/*
* Funambol is a mobile platform developed by Funambol, Inc.
* Copyright (C) 2003 - 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.model.calendar;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.SortedSet;
import java.util.TreeSet;
import com.funambol.common.pim.model.common.PropertyWithTimeZone;
import com.funambol.common.pim.model.utility.TimeUtils;
import com.funambol.util.StringUtil;
/**
* This class represents the recurrence pattern of a calendar item.
*
* @version $Id: RecurrencePattern.java,v 1.7 2008-06-24 12:01:27 mauro Exp $
*/
public class RecurrencePattern extends PropertyWithTimeZone {
// --------------------------------------------------------------- Constants
//
// Values for frequency
//
public static final byte TYPE_DAYLY = 0; // deprecated (wrong spelling)
public static final byte TYPE_DAILY = 0; // use this
public static final byte TYPE_WEEKLY = 1;
public static final byte TYPE_MONTHLY = 2;
public static final byte TYPE_MONTH_NTH = 3;
public static final byte TYPE_YEARLY = 5;
public static final byte TYPE_YEAR_NTH = 6;
//
// Values for dayOfWeekMask
//
public static final byte DAY_OF_WEEK_SUNDAY = 1;
public static final byte DAY_OF_WEEK_MONDAY = 2;
public static final byte DAY_OF_WEEK_TUESDAY = 4;
public static final byte DAY_OF_WEEK_WEDNESDAY = 8;
public static final byte DAY_OF_WEEK_THURSDAY = 16;
public static final byte DAY_OF_WEEK_FRIDAY = 32;
public static final byte DAY_OF_WEEK_SATURDAY = 64;
public static final short ALL_DAYS_MASK =
DAY_OF_WEEK_SUNDAY +
DAY_OF_WEEK_MONDAY +
DAY_OF_WEEK_TUESDAY +
DAY_OF_WEEK_WEDNESDAY +
DAY_OF_WEEK_THURSDAY +
DAY_OF_WEEK_FRIDAY +
DAY_OF_WEEK_SATURDAY ;
public static final short UNSPECIFIED = 0;
// -------------------------------------------------------------- Properties
private short frequency; // 0 daily
// 1 weekly
// 2 monthly
// 3 month n-th
// 5 yearly
// 6 year n-th
private int interval;
private short monthOfYear;
private short dayOfMonth;
private short dayOfWeekMask; // A combination (sum) of:
// 1 Sunday
// 2 Monday
// 4 Tuesday
// 8 Wednesday
// 16 Thursday
// 32 Friday
// 64 Saturday
private short instance;
private String startDatePattern;
private boolean noEndDate;
private String endDatePattern;
private int occurrences = -1; // -1 means no occurrences specified
private List<ExceptionToRecurrenceRule> exceptions =
new ArrayList<ExceptionToRecurrenceRule>();
/**
* Returns the recurrence frequency as a number.
*
* @return value of property frequency
*/
public short getTypeId() {
return frequency;
}
/**
* Returns the interval.
*
* @return Value of property interval
*/
public int getInterval() {
return interval;
}
/**
* Returns the month of year.
*
* @return Value of property monthOfYear
*/
public short getMonthOfYear() {
return monthOfYear;
}
/**
* Returns the day-of-week mask.
*
* @return Value of property dayOfWeekMask
*/
public short getDayOfWeekMask() {
return dayOfWeekMask;
}
/**
* Returns the day of the month.
*
* @return value of property dayOfMonth
*/
public short getDayOfMonth() {
return dayOfMonth;
}
/**
* Returns the instance number.
*
* @return value of property instance
*/
public short getInstance() {
return instance;
}
/**
* Returns the start date pattern.
*
* @return value of property startDatePattern
*/
public String getStartDatePattern() {
return startDatePattern;
}
/**
* Returns whether the pattern has no end date set.
*
* @return true if the pattern has no end date set, false otherwise
*/
public boolean isNoEndDate() {
return noEndDate;
}
/**
* Setter for property noEndDate.
*
* @param noEndDate new value of property noEndDate
*/
public void setNoEndDate(boolean noEndDate) {
this.noEndDate = noEndDate;
}
/**
* Returns the end date pattern.
*
* @return value of property endDatePattern
*/
public String getEndDatePattern() {
return endDatePattern;
}
/**
* Set the end date pattern.
*
* @param date value of property endDatePattern
*/
public void setEndDatePattern(String date) {
endDatePattern = date;
}
/**
* Returns the number of occurrences.
*
* @return value of property occurrences
*/
public int getOccurrences(){
return occurrences;
}
/**
* Setter for property occurrences.
*
* @param occurrences new value of property occurrences
*/
public void setOccurrences(int occurrences) {
this.occurrences = occurrences;
}
// ------------------------------------------------------------- Private data
static private Map<String, String> typeDesc = new HashMap<String, String>(6);
static {
typeDesc.put(String.valueOf(TYPE_DAILY) ,"D" );
typeDesc.put(String.valueOf(TYPE_WEEKLY) ,"W" );
typeDesc.put(String.valueOf(TYPE_MONTHLY) ,"MD");
typeDesc.put(String.valueOf(TYPE_MONTH_NTH),"MP");
typeDesc.put(String.valueOf(TYPE_YEARLY) ,"YM");
typeDesc.put(String.valueOf(TYPE_YEAR_NTH) ,"YM"); // same as above
}
// ------------------------------------------------------------ Constructors
/**
* Creates a new instance of RecurrencePattern. Property occurrences will be
* kept at -1 (unspecified).
* Client classes can use <i>getXxxRecurrencePattern()</i> instead of this
* constructor.
*
* @param frequency
* @param interval
* @param monthOfYear
* @param dayOfMonth
* @param dayOfWeekMask
* @param instance
* @param startDatePattern
* @param endDatePattern
* @param noEndDate
*/
public RecurrencePattern(short type ,
int interval ,
short monthOfYear ,
short dayOfMonth ,
short dayOfWeekMask ,
short instance ,
String startDatePattern,
String endDatePattern ,
boolean noEndDate ) {
this.frequency = type ;
this.interval = interval ;
this.monthOfYear = monthOfYear ;
this.dayOfMonth = dayOfMonth ;
this.dayOfWeekMask = dayOfWeekMask ;
this.instance = instance ;
this.startDatePattern = startDatePattern;
this.endDatePattern = endDatePattern ;
this.noEndDate = noEndDate ;
// It's strongly recommended to call fix() after using this constructor
}
/**
* Creates a new instance of RecurrencePattern.
* Client classes can use <i>getXxxRecurrencePattern()</i> instead of this
* constructor.
*
* @param frequency
* @param interval
* @param monthOfYear
* @param dayOfMonth
* @param dayOfWeekMask
* @param instance
* @param startDatePattern
* @param endDatePattern
* @param noEndDate
* @param occurrences
*/
public RecurrencePattern(short type ,
int interval ,
short monthOfYear ,
short dayOfMonth ,
short dayOfWeekMask ,
short instance ,
String startDatePattern ,
String endDatePattern ,
boolean noEndDate ,
int occurrences ) {
this(type,
interval,
monthOfYear,
dayOfMonth,
dayOfWeekMask,
instance,
startDatePattern,
endDatePattern,
noEndDate);
this.occurrences = occurrences;
// It's strongly recommended to call fix() after using this constructor
}
// ------------------------------------------------------- Daily recurrences
/**
* Daily recurrence with start and end dates.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getDailyRecurrencePattern(int interval ,
String startDatePattern,
String endDatePattern )
throws RecurrencePatternException {
validateInterval(interval);
validateDate(startDatePattern);
validateDate(endDatePattern);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
endDatePattern,
false);
}
/**
* Daily recurrence with start and end dates.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param dayOfWeekMask days when the event or task occurs
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getDailyRecurrencePattern(int interval ,
String startDatePattern,
String endDatePattern ,
short dayOfWeekMask )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
validateDate(endDatePattern);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
endDatePattern,
false);
}
/**
* Daily recurrence with start, end dates and noEndDate.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the pattern without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern,
String endDatePattern ,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDate(startDatePattern);
if (!noEndDate) {
validateDate(endDatePattern);
}
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate);
}
/**
* Daily recurrence with start, end dates and noEndDate.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @param dayOfWeekMask days when the event or task occurs
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern,
String endDatePattern ,
boolean noEndDate ,
short dayOfWeekMask )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
if (!noEndDate) {
validateDate(endDatePattern);
}
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate);
}
/**
* Daily recurrence
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern,
String endDatePattern ,
boolean noEndDate ,
int occurrences )
throws RecurrencePatternException {
validateInterval(interval);
validateDate(startDatePattern);
if (!noEndDate && occurrences < 1) {
validateDate(endDatePattern);
}
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate,
occurrences);
}
/**
* Daily recurrence.
*
* @param interval how many days between two recurrence
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @param dayOfWeekMask days when the event or task occurs
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern,
String endDatePattern ,
boolean noEndDate ,
int occurrences ,
short dayOfWeekMask )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
if (!noEndDate && occurrences < 1) {
validateDate(endDatePattern);
}
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate,
occurrences);
}
/**
* Infinite daily recurrence.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern )
throws RecurrencePatternException {
validateInterval(interval);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
null,
false);
}
/**
* Inifinite daily recurrence.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param dayOfWeekMask days when the event or task occurs
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern ,
short dayOfWeekMask )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
null,
false);
}
/**
* Infinite daily recurrence.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern ,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
null,
noEndDate);
}
/**
* Infinite daily recurrence.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @param dayOfWeekMask days when the event or task occurs
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern ,
boolean noEndDate ,
short dayOfWeekMask )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
null,
noEndDate);
}
/**
* Daily recurrence.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern ,
boolean noEndDate ,
int occurrences )
throws RecurrencePatternException {
validateInterval(interval);
validateDate(startDatePattern);
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
null,
noEndDate,
occurrences);
}
/**
* Daily recurrence.
*
* @param interval how many days between two recurrences
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @param dayOfWeekMask days when the event or task occurs
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*
*/
public static RecurrencePattern getDailyRecurrencePattern( int interval ,
String startDatePattern ,
boolean noEndDate ,
int occurrences ,
short dayOfWeekMask )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_DAILY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
null,
noEndDate,
occurrences);
}
// ------------------------------------------------------ Weekly recurrences
/**
* Weekly recurrence with start and end dates.
*
* @param interval how many weeks between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getWeeklyRecurrencePattern(int interval,
short dayOfWeekMask,
String startDatePattern,
String endDatePattern )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
validateDate(endDatePattern);
return new RecurrencePattern(TYPE_WEEKLY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
endDatePattern,
false);
}
/**
* Weekly recurrence with start, end dates and noEndDate.
*
* @param interval how many weeks between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getWeeklyRecurrencePattern(int interval,
short dayOfWeekMask,
String startDatePattern,
String endDatePattern ,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
if (!noEndDate) {
validateDate(endDatePattern);
}
return new RecurrencePattern(TYPE_WEEKLY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate);
}
/**
* Weekly recurrence.
*
* @param interval how many weeks between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getWeeklyRecurrencePattern(int interval,
short dayOfWeekMask,
String startDatePattern,
String endDatePattern ,
boolean noEndDate,
int occurrences)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
if (!noEndDate && occurrences < 1) {
validateDate(endDatePattern);
}
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_WEEKLY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate,
occurrences);
}
/**
* Infinite weekly recurrence
*
* @param interval how many days between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param startDatePattern start date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getWeeklyRecurrencePattern(int interval,
short dayOfWeekMask,
String startDatePattern)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_WEEKLY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
null,
false);
}
/**
* Infinite weekly recurrence
*
* @param interval how many days between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getWeeklyRecurrencePattern(int interval,
short dayOfWeekMask,
String startDatePattern,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_WEEKLY,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
UNSPECIFIED,
startDatePattern,
null,
noEndDate);
}
// ----------------------------------------------------- Monthly recurrences
/**
* Monthly recurrence with start and end dates.
*
* @param interval how many months between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getMonthlyRecurrencePattern(int interval,
short dayOfMonth,
String startDatePattern,
String endDatePattern )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateDate(startDatePattern);
validateDate(endDatePattern);
return new RecurrencePattern(TYPE_MONTHLY,
interval,
UNSPECIFIED,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
endDatePattern,
false);
}
/**
* Monthly recurrence.
*
* @param interval how many months between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getMonthlyRecurrencePattern(int interval,
short dayOfMonth,
String startDatePattern,
String endDatePattern ,
boolean noEndDate,
int occurrences)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateDate(startDatePattern);
if (!noEndDate && occurrences < 1) {
validateDate(endDatePattern);
}
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_MONTHLY,
interval,
UNSPECIFIED,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate,
occurrences);
}
/**
* Monthly recurrence with start, end dates and noEndDate.
*
* @param interval how many months between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getMonthlyRecurrencePattern(int interval,
short dayOfMonth,
String startDatePattern,
String endDatePattern ,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateDate(startDatePattern);
if (!noEndDate) {
validateDate(endDatePattern);
}
return new RecurrencePattern(TYPE_MONTHLY,
interval,
UNSPECIFIED,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate);
}
/**
* Infinite monthly recurrence.
*
* @param interval how many days between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param startDatePattern start date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getMonthlyRecurrencePattern(int interval,
short dayOfMonth,
String startDatePattern )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_MONTHLY,
interval,
UNSPECIFIED,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
null,
false);
}
/**
* Monthly recurrence.
*
* @param interval how many days between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getMonthlyRecurrencePattern(int interval,
short dayOfMonth,
String startDatePattern,
boolean noEndDate,
int occurrences )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateDate(startDatePattern);
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_MONTHLY,
interval,
UNSPECIFIED,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
null,
noEndDate,
occurrences);
}
/**
* Infinite monthly recurrence.
*
* @param interval how many days between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getMonthlyRecurrencePattern(int interval,
short dayOfMonth,
String startDatePattern,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_MONTHLY,
interval,
UNSPECIFIED,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
null,
noEndDate);
}
/**
* Monthly day-of-week-based recurrence with start and end dates.
*
* @param interval how many months between two recurrences
* @param dayOfWeekMask see below
* @param instance the <i>instance</i> of <i>dayOfWeekMask</i> of every
* <i>interval</i> months
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wront parameters
*/
public static RecurrencePattern getMonthNthRecurrencePattern(int interval ,
short dayOfWeekMask,
short instance,
String startDatePattern,
String endDatePattern )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateInstance(instance);
validateDate(startDatePattern);
validateDate(endDatePattern);
return new RecurrencePattern(TYPE_MONTH_NTH,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
instance,
startDatePattern,
endDatePattern,
false);
}
/**
* Monthly day-of-week-based recurrence with start, end dates and noEndDate.
*
* @param interval how many months between two recurrences
* @param dayOfWeekMask see below
* @param instance the <i>instance</i> of <i>dayOfWeekMask</i> of every
* <i>interval</i> months
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getMonthNthRecurrencePattern(int interval ,
short dayOfWeekMask,
short instance,
String startDatePattern,
String endDatePattern ,
boolean noEndDate,
int occurrences)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateInstance(instance);
validateDate(startDatePattern);
if (!noEndDate && occurrences < 1) {
validateDate(endDatePattern);
}
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_MONTH_NTH,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
instance,
startDatePattern,
endDatePattern,
noEndDate,
occurrences);
}
/**
* Monthly day-of-week-based recurrence with start and end dates.
*
* @param interval how many months between two recurrences
* @param dayOfWeekMask see below
* @param instance the <i>instance</i> of <i>dayOfWeekMask</i> of every <i>interval</i> months
* @param startDatePattern start date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getMonthNthRecurrencePattern(int interval ,
short dayOfWeekMask,
short instance,
String startDatePattern )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateInstance(instance);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_MONTH_NTH,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
instance,
startDatePattern,
null,
false);
}
/**
* Monthly day-of-week-based recurrence with start and end dates.
*
* @param interval how many months between two recurrences
* @param dayOfWeekMask see below
* @param instance the <i>instance</i> of <i>dayOfWeekMask</i> of every <i>interval</i> months
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getMonthNthRecurrencePattern(int interval ,
short dayOfWeekMask,
short instance,
String startDatePattern,
boolean noEndDate )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateInstance(instance);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_MONTH_NTH,
interval,
UNSPECIFIED,
UNSPECIFIED,
dayOfWeekMask,
instance,
startDatePattern,
null,
noEndDate);
}
// ------------------------------------------------------ Yearly recurrences
/**
* Yearly recurrence with start, end dates and noEndDate.
*
* @param interval how many years between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearlyRecurrencePattern(int interval,
short dayOfMonth,
short monthOfYear,
String startDatePattern,
String endDatePattern ,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateMonthOfYear(monthOfYear);
validateDate(startDatePattern);
if (!noEndDate) {
validateDate(endDatePattern);
}
return new RecurrencePattern(TYPE_YEARLY,
interval,
monthOfYear,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate);
}
/**
* Yearly recurrence.
*
* @param interval how many years between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearlyRecurrencePattern(int interval,
short dayOfMonth,
short monthOfYear,
String startDatePattern,
String endDatePattern ,
boolean noEndDate,
int occurrences)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateMonthOfYear(monthOfYear);
validateDate(startDatePattern);
if (!noEndDate && occurrences < 1) {
validateDate(endDatePattern);
}
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_YEARLY,
interval,
monthOfYear,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
endDatePattern,
noEndDate,
occurrences);
}
/**
* Yearly recurrence with start, end dates and noEndDate
*
* @param interval how many years between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearlyRecurrencePattern(int interval,
short dayOfMonth,
short monthOfYear,
String startDatePattern,
String endDatePattern)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateMonthOfYear(monthOfYear);
validateDate(startDatePattern);
validateDate(endDatePattern);
return new RecurrencePattern(TYPE_YEARLY,
interval,
monthOfYear,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
endDatePattern,
false);
}
/**
* Infinite yearly recurrence.
*
* @param interval how many years between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param startDatePattern start date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearlyRecurrencePattern(int interval,
short dayOfMonth,
short monthOfYear,
String startDatePattern )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateMonthOfYear(monthOfYear);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_YEARLY,
interval,
monthOfYear,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
null,
false);
}
/**
* Infinite yearly recurrence.
*
* @param interval how many years between two recurrences
* @param dayOfMonth day of month (1-31) when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearlyRecurrencePattern(int interval,
short dayOfMonth,
short monthOfYear,
String startDatePattern,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfMonth(dayOfMonth);
validateMonthOfYear(monthOfYear);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_YEARLY,
interval,
monthOfYear,
dayOfMonth,
UNSPECIFIED,
UNSPECIFIED,
startDatePattern,
null,
noEndDate);
}
/**
* Yearly day-of-week-based recurrence with start, end dates and noEndDate.
*
* @param interval how many years between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param instance every <i>instance</i> of <i>dayOfWeekMask</i> of
* <i>monthOfYear</i>
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearNthRecurrencePattern(int interval,
short dayOfWeekMask,
short monthOfYear,
short instance,
String startDatePattern,
String endDatePattern ,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateMonthOfYear(monthOfYear);
validateInstance(instance);
validateDate(startDatePattern);
if (!noEndDate) {
validateDate(endDatePattern);
}
return new RecurrencePattern(TYPE_YEAR_NTH,
interval,
monthOfYear,
UNSPECIFIED,
dayOfWeekMask,
instance,
startDatePattern,
endDatePattern,
noEndDate);
}
/**
* Yearly day-of-week-based recurrence.
*
* @param interval how many years between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param instance every <i>instance</i> of <i>dayOfWeekMask</i> of
* <i>monthOfYear</i>
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @param noEndDate is the recurrence without end date?
* @param occurrences number of occurrences
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearNthRecurrencePattern(int interval,
short dayOfWeekMask,
short monthOfYear,
short instance,
String startDatePattern,
String endDatePattern ,
boolean noEndDate,
int occurrences)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateMonthOfYear(monthOfYear);
validateInstance(instance);
validateDate(startDatePattern);
if (!noEndDate && occurrences < 1) {
validateDate(endDatePattern);
}
validateOccurrences(occurrences);
return new RecurrencePattern(TYPE_YEAR_NTH,
interval,
monthOfYear,
UNSPECIFIED,
dayOfWeekMask,
instance,
startDatePattern,
endDatePattern,
noEndDate,
occurrences);
}
/**
* Yearly day-of-week-based recurrence with start and end dates.
*
* @param interval how many years between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param instance every <i>instance</i> of <i>dayOfWeekMask</i> of
* <i>monthOfYear</i>
* @param startDatePattern start date pattern
* @param endDatePattern end date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearNthRecurrencePattern(int interval,
short dayOfWeekMask,
short monthOfYear,
short instance,
String startDatePattern,
String endDatePattern)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateMonthOfYear(monthOfYear);
validateInstance(instance);
validateDate(startDatePattern);
validateDate(endDatePattern);
return new RecurrencePattern(TYPE_YEAR_NTH,
interval,
monthOfYear,
UNSPECIFIED,
dayOfWeekMask,
instance,
startDatePattern,
endDatePattern,
false);
}
/**
* Yearly day-of-week-based recurrence with start and end dates.
*
* @param interval how many years between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param instance every <i>instance</i> of <i>dayOfWeekMask</i> of
* <i>monthOfYear</i>
* @param startDatePattern start date pattern
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearNthRecurrencePattern(int interval,
short dayOfWeekMask,
short monthOfYear,
short instance,
String startDatePattern )
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateMonthOfYear(monthOfYear);
validateInstance(instance);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_YEAR_NTH,
interval,
monthOfYear,
UNSPECIFIED,
dayOfWeekMask,
instance,
startDatePattern,
null,
false);
}
/**
* Yearly day-of-week-based recurrence with start and end dates.
*
* @param interval how many years between two recurrences
* @param dayOfWeekMask days when the event or task occurs
* @param monthOfYear month (1-12) of the year when the event or task occurs
* @param instance every <i>instance</i> of <i>dayOfWeekMask</i> of
* <i>monthOfYear</i>
* @param startDatePattern start date pattern
* @param noEndDate is the recurrence without end date?
* @return the newly created RecurrencePattern object
* @throws RecurrencePatternException in case of wrong parameters
*/
public static RecurrencePattern getYearNthRecurrencePattern(int interval,
short dayOfWeekMask,
short monthOfYear,
short instance,
String startDatePattern,
boolean noEndDate)
throws RecurrencePatternException {
validateInterval(interval);
validateDayOfWeekMask(dayOfWeekMask);
validateMonthOfYear(monthOfYear);
validateInstance(instance);
validateDate(startDatePattern);
return new RecurrencePattern(TYPE_YEAR_NTH,
interval,
monthOfYear,
UNSPECIFIED,
dayOfWeekMask,
instance,
startDatePattern,
null,
noEndDate);
}
// ---------------------------------------------------------- Public methods
/**
* Gives a vCalendar short form for the recurrence frequency.
*
*@return "D" for daily recurrence
* "W" for weekly recurrence
* "MP" for monthly recurrence (monthly by position)
* "MD" for monthly day-of-week-based recurrence (monthly by day)
* "YM" for yearly recurrence (yearly by month)
*/
public String getTypeDesc() {
return typeDesc.get(String.valueOf(frequency));
}
/**
* Return a list of abbreviations of days of week in which the task or event
* recurs.
*
* @return the list of days of the week ("SU", "MO", etc.)
*/
public List<String> getDayOfWeek() {
ArrayList<String> days = new ArrayList<String>();
if ((dayOfWeekMask & DAY_OF_WEEK_SUNDAY) != 0) {
days.add("SU");
}
if ((dayOfWeekMask & DAY_OF_WEEK_MONDAY) != 0) {
days.add("MO");
}
if ((dayOfWeekMask & DAY_OF_WEEK_TUESDAY) != 0) {
days.add("TU");
}
if ((dayOfWeekMask & DAY_OF_WEEK_WEDNESDAY) != 0) {
days.add("WE");
}
if ((dayOfWeekMask & DAY_OF_WEEK_THURSDAY) != 0) {
days.add("TH");
}
if ((dayOfWeekMask & DAY_OF_WEEK_FRIDAY) != 0) {
days.add("FR");
}
if ((dayOfWeekMask & DAY_OF_WEEK_SATURDAY) != 0) {
days.add("SA");
}
return days;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer("<RecurrencePattern [");
sb.append("DayOfMonth: ").append(dayOfMonth);
sb.append(", DayOfWeekMask: ").append(dayOfWeekMask);
sb.append(", EndDatePattern: ").append(endDatePattern);
sb.append(", Instance: ").append(instance);
sb.append(", Interval: ").append(interval);
sb.append(", MonthOfYear: ").append(monthOfYear);
sb.append(", NoEndDate: ").append(noEndDate);
sb.append(", Occurrences: ").append(occurrences);
sb.append(", StartDatePattern: ").append(startDatePattern);
sb.append(", Type: ").append(frequency);
sb.append("]>");
return sb.toString();
}
/**
* Gets the exception list, duplicate-free and ordered.
*
* @return the exceptions as a List collection
*/
public List<ExceptionToRecurrenceRule> getExceptions() {
SortedSet<ExceptionToRecurrenceRule> set =
new TreeSet<ExceptionToRecurrenceRule>(exceptions);
exceptions = new ArrayList<ExceptionToRecurrenceRule>(set);
return exceptions;
}
/**
* Sets the exception list.
* Being a list, there could be duplicates but they will be removed by the
* getter in any case.
*
* @param exceptions the exceptions as a List collection
*/
public void setExceptions(List<ExceptionToRecurrenceRule> exceptions) {
this.exceptions = exceptions;
}
/**
* Sets the exception set.
* It is still saved internally as an ArrayList though.
*
* @param exceptions the exceptions as a SortedSet collection
*/
public void setExceptions(SortedSet<ExceptionToRecurrenceRule> exceptions) {
this.exceptions = new ArrayList<ExceptionToRecurrenceRule>(exceptions);
}
// --------------------------------------------------------- Private methods
/**
* Gets the GregorianCalendar object corresponding to the given date.
*
* @param date in "YYYYMMDD..." format
* @return an instance of the GregorianCalendar class
*/
private GregorianCalendar getGregorianCalendar(String date) {
int year = Integer.parseInt(date.substring(0, 4));
int month = Integer.parseInt(date.substring(4, 6));
int day = Integer.parseInt(date.substring(6, 8));
return new GregorianCalendar(year, month - 1, day);
}
/**
* Checks whether a given day is included in the mask.
*
* @param day the day in the RecurrencePattern.DAY_OF_WEEK_*DAY format (as a
* byte)
* @param mask the day-of-week mask
* @return true only if day is in mask
*/
private boolean isDayInMask(byte day, int mask) {
return ((mask % (2 * day)) >= day);
}
/**
* Gets the week day of a given date.
*
* @param date in "YYYYMMDD..." format
* @return the day in the RecurrencePattern.DAY_OF_WEEK_*DAY format (as a
* byte)
*/
private byte getWeekDay(String date) {
switch(getGregorianCalendar(date)
.get(java.util.Calendar.DAY_OF_WEEK)) { // Ugly but safe
case java.util.Calendar.SUNDAY:
return DAY_OF_WEEK_SUNDAY;
case java.util.Calendar.MONDAY:
return DAY_OF_WEEK_MONDAY;
case java.util.Calendar.TUESDAY:
return DAY_OF_WEEK_TUESDAY;
case java.util.Calendar.WEDNESDAY:
return DAY_OF_WEEK_WEDNESDAY;
case java.util.Calendar.THURSDAY:
return DAY_OF_WEEK_THURSDAY;
case java.util.Calendar.FRIDAY:
return DAY_OF_WEEK_FRIDAY;
case java.util.Calendar.SATURDAY:
return DAY_OF_WEEK_SATURDAY;
}
return 0; // This shouldn't happen!
}
/**
* Computes which instance of its week day a given date is in its month (eg,
* the 3th Friday of the month).
*
* @param date in "YYYYMMDD..." format
* @return a positive short representing the (forward) ordinal position of
* that week day in the month
*/
private short getWeekDayInstance(String date) {
short day = Short.parseShort(date.substring(6, 8));
return (short) ((day + 6) / 7); // Yes, it works
}
/**
* Computes which instance of its week day a given date is in its month,
* counting in the reverse direction (eg, the 2nd to the last Friday of the
* month).
*
* @param date in "YYYYMMDD..." format
* @return a negative short representing the (backward) ordinal position of
* that week day in the month
*/
private short getBackwardWeekDayInstance(String date) {
GregorianCalendar greg = getGregorianCalendar(date);
return (short) (-1 + greg.get(java.util.Calendar.DAY_OF_WEEK_IN_MONTH) -
greg.getActualMaximum(java.util.Calendar.DAY_OF_WEEK_IN_MONTH));
}
/**
* Gets the month day of a given date.
*
* @param date in "YYYYMMDD..." format
* @return a positive short representing the (forward) ordinal position of
* the day in the month
*/
private short getMonthDay(String date) {
return Short.parseShort(date.substring(6, 8));
}
/**
* Gets the backward-counted position of a given date in the month.
*
* @param date in "YYYYMMDD..." format
* @return a negative short representing the backward ordinal position of
* the day in the month
*/
private short getBackwardMonthDay(String date) {
GregorianCalendar greg = getGregorianCalendar(date);
return (short) (-1 + greg.get(java.util.Calendar.DAY_OF_MONTH) -
greg.getActualMaximum(java.util.Calendar.DAY_OF_MONTH));
}
/**
* Gets the month of a given date.
*
* @param date in "YYYYMMDD..." format
* @return a short representing the month (1 = January, 2 = February etc.)
*/
private short getMonth(String date) {
return Short.parseShort(date.substring(4, 6));
}
/**
* Fixes missing data on the basis of the startDatePattern field, according
* to the inference rules prescribed by the specifications (missing data
* must be inferred by the start date).
*
* @return true if a fix was needed
* @throws RecurrencePatternException if no automatic fix was possible
*/
public boolean fix() throws RecurrencePatternException {
boolean fixed = false;
String localStartDate;
try {
if (timeZone == null) {
localStartDate = startDatePattern;
} else {
localStartDate =
TimeUtils.convertUTCDateToLocal(startDatePattern ,
TimeZone.getTimeZone(timeZone));
}
} catch (Exception e) {
throw new RecurrencePatternException(
"Conversion of start date pattern to local time failed");
}
String yyyyMMddStartDatePattern = localStartDate.replaceAll("-", "");
try {
switch(frequency) {
case TYPE_DAILY:
// Does nothing
break;
case TYPE_YEAR_NTH:
short month = getMonth(yyyyMMddStartDatePattern);
if (month != monthOfYear) {
month = monthOfYear;
fixed = true;
}
// Falls through
case TYPE_MONTH_NTH:
if (instance != getBackwardWeekDayInstance(yyyyMMddStartDatePattern)) {
short startWeekDayInstance =
getWeekDayInstance(yyyyMMddStartDatePattern);
if (startWeekDayInstance != instance) {
instance = startWeekDayInstance;
fixed = true;
}
}
// Falls through
case TYPE_WEEKLY:
byte startWeekDay = getWeekDay(yyyyMMddStartDatePattern);
if (!isDayInMask(startWeekDay, dayOfWeekMask)) {
dayOfWeekMask += startWeekDay;
fixed = true;
}
break;
case TYPE_YEARLY:
month = getMonth(yyyyMMddStartDatePattern);
if (month != monthOfYear) {
monthOfYear = month;
fixed = true;
}
// Falls through
case TYPE_MONTHLY:
if (dayOfMonth != getBackwardMonthDay(yyyyMMddStartDatePattern)) {
short startMonthDay = getMonthDay(yyyyMMddStartDatePattern);
if (startMonthDay != dayOfMonth) {
dayOfMonth = startMonthDay;
fixed = true;
}
}
break;
default:
throw new RecurrencePatternException("Type " + frequency +
"not implemented");
}
} catch (Exception e) {
throw new RecurrencePatternException("RecurrencePattern: Format " +
"error found. " + e);
}
return fixed;
}
// ------------------------------------------------------ Validation methods
/**
* Validates a day-of-week mask. To be valid it must be >= 0 and less
* than ALL_DAYS_MASK.
*
* @param dayOfWeekMask the mask
* @throws RecurrencePatternException if the validation fails
*/
private static void validateDayOfWeekMask(short dayOfWeekMask)
throws RecurrencePatternException {
if (dayOfWeekMask < 0 || dayOfWeekMask > ALL_DAYS_MASK) {
throw new RecurrencePatternException("dayOfWeekMask outside range [0, ALL_DAYS_MASK]: " + dayOfWeekMask );
}
}
/**
* Validates the number of occurrences. It must be >= 0.
*
* @param occurrences the number of occurrences
* @throws RecurrencePatternException if the validation fails
*/
private static void validateOccurrences(int occurrences)
throws RecurrencePatternException {
if (occurrences < -1) {
throw new RecurrencePatternException( "occurrences is not greater or equals than 0: " + occurrences);
}
}
/**
* Validates a month of the year. It must be in the interval [1, 12].
*
* @param monthOfYear the month
* @throws RecurrencePatternException if the validation fails
*/
private static void validateMonthOfYear(short monthOfYear)
throws RecurrencePatternException {
if (monthOfYear < 1 && monthOfYear > 12) {
throw new RecurrencePatternException("monthOfYear outside range ([1, 12]: " + monthOfYear);
}
}
/**
* Validates an instance number.
* There are no requirements for instance numbers, therefore it is always
* validated, but this method is here in any case for consistence's sake.
*
* @param instance the instance number
* @throws RecurrencePatternException if the validation fails
*/
private static void validateInstance(int instance)
throws RecurrencePatternException {
// Do nothing
}
/**
* Validates the interval number.
* The interval can be equal to 0 when:
* <ul>
* <li>the recurrence frequency is Daily</li>
* <li>the recurrence value is Every Week Day</li>
* </ul>
*
* @param interval the interval of recurrence
*
* @throws RecurrencePatternException in case of errors
*/
private static void validateInterval(int interval)
throws RecurrencePatternException {
if (interval < 0) {
throw new RecurrencePatternException(
"interval is less than 0: " + interval);
}
}
/**
* Validates a date pattern. It must not be empty.
*
* @param datePattern a start date pattern or an end date pattern
* @throws RecurrencePatternException if the validation fails
*/
private static void validateDate(String datePattern)
throws RecurrencePatternException {
if (StringUtil.isNullOrEmpty(datePattern)) {
throw new RecurrencePatternException("The calendar item is recursive but a datePattern is empty");
}
}
/**
* Validates the day of the month. It must be in the interval [1, 31].
*
* @param dayOfMonth the day of the month
* @throws RecurrencePatternException if the validation fails
*/
private static void validateDayOfMonth(short dayOfMonth)
throws RecurrencePatternException {
if (dayOfMonth < 1 && dayOfMonth > 31) {
throw new RecurrencePatternException("dayOfMonth outside range [1, 31]: " + dayOfMonth);
}
}
}