| /* |
| ******************************************************************************* |
| * Copyright (C) 1996-2010, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| */ |
| |
| package com.ibm.icu.util; |
| |
| import java.util.Date; |
| |
| /** |
| * <b>Note:</b> The Holiday framework is a technology preview. |
| * Despite its age, is still draft API, and clients should treat it as such. |
| * |
| * Simple implementation of DateRule. |
| * @draft ICU 2.8 (retainAll) |
| * @provisional This API might change or be removed in a future release. |
| */ |
| public class SimpleDateRule implements DateRule |
| { |
| /** |
| * Construct a rule for a fixed date within a month |
| * |
| * @param month The month in which this rule occurs (0-based). |
| * @param dayOfMonth The date in that month (1-based). |
| * @draft ICU 2.8 |
| * @provisional This API might change or be removed in a future release. |
| */ |
| public SimpleDateRule(int month, int dayOfMonth) |
| { |
| this.month = month; |
| this.dayOfMonth = dayOfMonth; |
| this.dayOfWeek = 0; |
| } |
| |
| // temporary |
| /* package */SimpleDateRule(int month, int dayOfMonth, Calendar cal) |
| { |
| this.month = month; |
| this.dayOfMonth = dayOfMonth; |
| this.dayOfWeek = 0; |
| this.calendar = cal; |
| } |
| |
| /** |
| * Construct a rule for a weekday within a month, e.g. the first Monday. |
| * |
| * @param month The month in which this rule occurs (0-based). |
| * @param dayOfMonth A date within that month (1-based). |
| * @param dayOfWeek The day of the week on which this rule occurs. |
| * @param after If true, this rule selects the first dayOfWeek |
| * on or after dayOfMonth. If false, the rule selects |
| * the first dayOfWeek on or before dayOfMonth. |
| * @draft ICU 2.8 |
| * @provisional This API might change or be removed in a future release. |
| */ |
| public SimpleDateRule(int month, int dayOfMonth, int dayOfWeek, boolean after) |
| { |
| this.month = month; |
| this.dayOfMonth = dayOfMonth; |
| this.dayOfWeek = after ? dayOfWeek : -dayOfWeek; |
| } |
| |
| /** |
| * Return the first occurrance of the event represented by this rule |
| * that is on or after the given start date. |
| * |
| * @param start Only occurrances on or after this date are returned. |
| * |
| * @return The date on which this event occurs, or null if it |
| * does not occur on or after the start date. |
| * |
| * @see #firstBetween |
| * @draft ICU 2.8 |
| * @provisional This API might change or be removed in a future release. |
| */ |
| public Date firstAfter(Date start) |
| { |
| return doFirstBetween(start, null); |
| } |
| |
| /** |
| * Return the first occurrance of the event represented by this rule |
| * that is on or after the given start date and before the given |
| * end date. |
| * |
| * @param start Only occurrances on or after this date are returned. |
| * @param end Only occurrances before this date are returned. |
| * |
| * @return The date on which this event occurs, or null if it |
| * does not occur between the start and end dates. |
| * |
| * @see #firstAfter |
| * @draft ICU 2.8 |
| * @provisional This API might change or be removed in a future release. |
| */ |
| public Date firstBetween(Date start, Date end) |
| { |
| // Pin to the min/max dates for this rule |
| return doFirstBetween(start, end); |
| } |
| |
| /** |
| * Checks whether this event occurs on the given date. This does |
| * <em>not</em> take time of day into account; instead it checks |
| * whether this event and the given date are on the same day. |
| * This is useful for applications such as determining whether a given |
| * day is a holiday. |
| * |
| * @param date The date to check. |
| * @return true if this event occurs on the given date. |
| * @draft ICU 2.8 |
| * @provisional This API might change or be removed in a future release. |
| */ |
| public boolean isOn(Date date) |
| { |
| Calendar c = calendar; |
| |
| synchronized(c) { |
| c.setTime(date); |
| |
| int dayOfYear = c.get(Calendar.DAY_OF_YEAR); |
| |
| c.setTime(computeInYear(c.get(Calendar.YEAR), c)); |
| |
| // System.out.println(" isOn: dayOfYear = " + dayOfYear); |
| // System.out.println(" holiday = " + c.get(Calendar.DAY_OF_YEAR)); |
| |
| return c.get(Calendar.DAY_OF_YEAR) == dayOfYear; |
| } |
| } |
| |
| /** |
| * Check whether this event occurs at least once between the two |
| * dates given. |
| * @draft ICU 2.8 |
| * @provisional This API might change or be removed in a future release. |
| */ |
| public boolean isBetween(Date start, Date end) |
| { |
| return firstBetween(start, end) != null; // TODO: optimize? |
| } |
| |
| private Date doFirstBetween(Date start, Date end) |
| { |
| Calendar c = calendar; |
| |
| synchronized(c) { |
| c.setTime(start); |
| |
| int year = c.get(Calendar.YEAR); |
| int mon = c.get(Calendar.MONTH); |
| |
| // If the rule is earlier in the year than the start date |
| // we have to go to the next year. |
| if (mon > this.month) { |
| year++; |
| } |
| |
| // Figure out when the rule lands in the given year |
| Date result = computeInYear(year, c); |
| |
| // If the rule is in the same month as the start date, it's possible |
| // to get a result that's before the start. If so, go to next year. |
| if (mon == this.month && result.before(start)) { |
| result = computeInYear(year+1, c); |
| } |
| |
| if (end != null && result.after(end)) { |
| return null; |
| } |
| return result; |
| } |
| } |
| |
| private Date computeInYear(int year, Calendar c) |
| { |
| synchronized(c) { |
| c.clear(); |
| c.set(Calendar.ERA, c.getMaximum(Calendar.ERA)); |
| c.set(Calendar.YEAR, year); |
| c.set(Calendar.MONTH, month); |
| c.set(Calendar.DATE, dayOfMonth); |
| |
| //System.out.println(" computeInYear: start at " + c.getTime().toString()); |
| |
| if (dayOfWeek != 0) { |
| c.setTime(c.getTime()); // JDK 1.1.2 workaround |
| int weekday = c.get(Calendar.DAY_OF_WEEK); |
| |
| //System.out.println(" weekday = " + weekday); |
| //System.out.println(" dayOfYear = " + c.get(Calendar.DAY_OF_YEAR)); |
| |
| int delta = 0; |
| if (dayOfWeek > 0) { |
| // We want the first occurrance of the given day of the week |
| // on or after the specified date in the month. |
| delta = (dayOfWeek - weekday + 7) % 7; |
| } |
| else { |
| // We want the first occurrance of the (-dayOfWeek) |
| // on or before the specified date in the month. |
| delta = -((dayOfWeek + weekday + 7) % 7); |
| } |
| //System.out.println(" adding " + delta + " days"); |
| c.add(Calendar.DATE, delta); |
| } |
| |
| return c.getTime(); |
| } |
| } |
| |
| /** |
| * @draft ICU 2.8 |
| * @provisional This API might change or be removed in a future release. |
| */ |
| // public void setCalendar(Calendar c) { |
| // calendar = c; |
| // } |
| |
| private static GregorianCalendar gCalendar = new GregorianCalendar(); |
| |
| private Calendar calendar = gCalendar; |
| |
| private int month; |
| private int dayOfMonth; |
| private int dayOfWeek; |
| } |