001    /*
002     * $Id: CalendarUtils.java 3100 2008-10-14 22:33:10Z rah003 $
003     *
004     * Copyright 2007 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    package org.jdesktop.swingx.calendar;
022    
023    import java.util.Calendar;
024    import java.util.Date;
025    
026    /**
027     * Calendar manipulation.
028     * 
029     * PENDING: replace by something tested - as is c&p'ed dateUtils 
030     * to work on a calendar instead of using long
031     * 
032     * @author Jeanette Winzenburg
033     */
034    public class CalendarUtils {
035    
036        // Constants used internally; unit is milliseconds
037        @SuppressWarnings("unused")
038        public static final int ONE_MINUTE = 60*1000;
039        @SuppressWarnings("unused")
040        public static final int ONE_HOUR   = 60*ONE_MINUTE;
041        @SuppressWarnings("unused")
042        public static final int THREE_HOURS = 3 * ONE_HOUR;
043        @SuppressWarnings("unused")
044        public static final int ONE_DAY    = 24*ONE_HOUR;
045        
046        /**
047         * Adjusts the Calendar to the end of the day of the last day in DST in the
048         * current year or unchanged if  not using DST. Returns the calendar's date or null, if not 
049         * using DST.<p>
050         * 
051         * 
052         * @param calendar the calendar to adjust
053         * @return the end of day of the last day in DST, or null if not using DST.
054         */
055        public static Date getEndOfDST(Calendar calendar) {
056            if (!calendar.getTimeZone().useDaylightTime()) return null;
057            long old = calendar.getTimeInMillis();
058            calendar.set(Calendar.MONTH, Calendar.DECEMBER);
059            endOfMonth(calendar);
060            startOfDay(calendar);
061            for (int i = 0; i < 366; i++) {
062               calendar.add(Calendar.DATE, -1);
063               if (calendar.getTimeZone().inDaylightTime(calendar.getTime())) {
064                   endOfDay(calendar);
065                   return calendar.getTime();
066               }
067            }
068            calendar.setTimeInMillis(old);
069            return null;
070        }
071    
072        
073        /**
074         * Adjusts the Calendar to the end of the day of the first day in DST in the
075         * current year or unchanged if  not using DST. Returns the calendar's date or null, if not 
076         * using DST.<p>
077         * 
078         * Note: the start of the day of the first day in DST is ill-defined!
079         * 
080         * @param calendar the calendar to adjust
081         * @return the start of day of the first day in DST, or null if not using DST.
082         */
083        public static Date getStartOfDST(Calendar calendar) {
084            if (!calendar.getTimeZone().useDaylightTime()) return null;
085            long old = calendar.getTimeInMillis();
086            calendar.set(Calendar.MONTH, Calendar.JANUARY);
087            startOfMonth(calendar);
088            endOfDay(calendar);
089            for (int i = 0; i < 366; i++) {
090               calendar.add(Calendar.DATE, 1);
091               if (calendar.getTimeZone().inDaylightTime(calendar.getTime())) {
092                   endOfDay(calendar);
093                   return calendar.getTime();
094               }
095            }
096            calendar.setTimeInMillis(old);
097            return null;
098        }
099        /**
100         * Returns a boolean indicating if the given calendar represents the 
101         * start of a day (in the calendar's time zone). The calendar is unchanged.
102         * 
103         * @param calendar the calendar to check.
104         * 
105         * @return true if the calendar's time is the start of the day,
106         *   false otherwise.
107         */
108        public static boolean isStartOfDay(Calendar calendar) {
109            Calendar temp = (Calendar) calendar.clone();
110            temp.add(Calendar.MILLISECOND, -1);
111            return temp.get(Calendar.DATE) != calendar.get(Calendar.DATE);
112        }
113    
114        /**
115         * Returns a boolean indicating if the given calendar represents the 
116         * end of a day (in the calendar's time zone). The calendar is unchanged.
117         * 
118         * @param calendar the calendar to check.
119         * 
120         * @return true if the calendar's time is the end of the day,
121         *   false otherwise.
122         */
123        public static boolean isEndOfDay(Calendar calendar) {
124            Calendar temp = (Calendar) calendar.clone();
125            temp.add(Calendar.MILLISECOND, 1);
126            return temp.get(Calendar.DATE) != calendar.get(Calendar.DATE);
127        }
128        
129        /**
130         * Returns a boolean indicating if the given calendar represents the 
131         * start of a month (in the calendar's time zone). Returns true, if the time is 
132         * the start of the first day of the month, false otherwise. The calendar is unchanged.
133         * 
134         * @param calendar the calendar to check.
135         * 
136         * @return true if the calendar's time is the start of the first day of the month,
137         *   false otherwise.
138         */
139        public static boolean isStartOfMonth(Calendar calendar) {
140            Calendar temp = (Calendar) calendar.clone();
141            temp.add(Calendar.MILLISECOND, -1);
142            return temp.get(Calendar.MONTH) != calendar.get(Calendar.MONTH);
143        }
144    
145        /**
146         * Returns a boolean indicating if the given calendar represents the 
147         * end of a month (in the calendar's time zone). Returns true, if the time is 
148         * the end of the last day of the month, false otherwise. The calendar is unchanged.
149         * 
150         * @param calendar the calendar to check.
151         * 
152         * @return true if the calendar's time is the end of the last day of the month,
153         *   false otherwise.
154         */
155        public static boolean isEndOfMonth(Calendar calendar) {
156            Calendar temp = (Calendar) calendar.clone();
157            temp.add(Calendar.MILLISECOND, 1);
158            return temp.get(Calendar.MONTH) != calendar.get(Calendar.MONTH);
159        }
160        
161        /**
162         * Returns a boolean indicating if the given calendar represents the 
163         * start of a month (in the calendar's time zone). Returns true, if the time is 
164         * the start of the first day of the month, false otherwise. The calendar is unchanged.
165         * 
166         * @param calendar the calendar to check.
167         * 
168         * @return true if the calendar's time is the start of the first day of the month,
169         *   false otherwise.
170         */
171        public static boolean isStartOfWeek(Calendar calendar) {
172            Calendar temp = (Calendar) calendar.clone();
173            temp.add(Calendar.MILLISECOND, -1);
174            return temp.get(Calendar.WEEK_OF_YEAR) != calendar.get(Calendar.WEEK_OF_YEAR);
175        }
176        
177        /**
178         * Returns a boolean indicating if the given calendar represents the 
179         * end of a week (in the calendar's time zone). Returns true, if the time is 
180         * the end of the last day of the week, false otherwise. The calendar is unchanged.
181         * 
182         * @param calendar the calendar to check.
183         * 
184         * @return true if the calendar's time is the end of the last day of the week,
185         *   false otherwise.
186         */
187        public static boolean isEndOfWeek(Calendar calendar) {
188            Calendar temp = (Calendar) calendar.clone();
189            temp.add(Calendar.MILLISECOND, 1);
190            return temp.get(Calendar.WEEK_OF_YEAR) != calendar.get(Calendar.WEEK_OF_YEAR);
191        }
192        
193        /**
194         * Adjusts the calendar to the start of the current week.
195         * That is, first day of the week with all time fields cleared.
196         * @param calendar the calendar to adjust.
197         */
198        public static void startOfWeek(Calendar calendar) {
199            calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
200            startOfDay(calendar);
201        }
202    
203        /**
204         * Adjusts the calendar to the end of the current week.
205         * That is, last day of the week with all time fields at max.
206         * @param calendar the calendar to adjust.
207         */
208        public static void endOfWeek(Calendar calendar) {
209            startOfWeek(calendar);
210            calendar.add(Calendar.DATE, 7);
211            calendar.add(Calendar.MILLISECOND, -1);
212        }
213        
214        /**
215         * Adjusts the calendar to the end of the current week.
216         * That is, last day of the week with all time fields at max.
217         * The Date of the adjusted Calendar is
218         * returned. 
219         * 
220         * @param calendar calendar to adjust.
221         * @param date the Date to use.
222         * @return the end of the week of the given date
223         */
224        public static Date endOfWeek(Calendar calendar, Date date) {
225            calendar.setTime(date);
226            endOfWeek(calendar);
227            return calendar.getTime();
228        }
229        
230        /**
231         * Adjusts the calendar to the start of the current week.
232         * That is, last day of the week with all time fields at max.
233         * The Date of the adjusted Calendar is
234         * returned. 
235         * 
236         * @param calendar calendar to adjust.
237         * @param date the Date to use.
238         * @return the start of the week of the given date
239         */
240        public static Date startOfWeek(Calendar calendar, Date date) {
241            calendar.setTime(date);
242            startOfWeek(calendar);
243            return calendar.getTime();
244        }
245    
246        /**
247         * Adjusts the calendar to the start of the current month.
248         * That is, first day of the month with all time fields cleared.
249         * @param calendar
250         */
251        public static void startOfMonth(Calendar calendar) {
252            calendar.set(Calendar.DAY_OF_MONTH, 1);
253            startOfDay(calendar);
254        }
255    
256        /**
257         * Adjusts the calendar to the end of the current month.
258         * That is the last day of the month with all time-fields
259         * at max.
260         * 
261         * @param calendar
262         */
263        public static void endOfMonth(Calendar calendar) {
264            // start of next month
265            calendar.add(Calendar.MONTH, 1);
266            startOfMonth(calendar);
267            // one millisecond back
268            calendar.add(Calendar.MILLISECOND, -1);
269        }
270    
271    
272    
273        /**
274         * Adjust the given calendar to the first millisecond of the given date.
275         * that is all time fields cleared. The Date of the adjusted Calendar is
276         * returned. 
277         * 
278         * @param calendar calendar to adjust.
279         * @param date the Date to use.
280         * @return the start of the day of the given date
281         */
282        public static Date startOfDay(Calendar calendar, Date date) {
283            calendar.setTime(date);
284            startOfDay(calendar);
285            return calendar.getTime();
286        }
287    
288    
289        /**
290         * Adjust the given calendar to the last millisecond of the given date.
291         * that is all time fields cleared. The Date of the adjusted Calendar is
292         * returned. 
293         * 
294         * @param calendar calendar to adjust.
295         * @param date the Date to use.
296         * @return the end of the day of the given date
297         */
298        public static Date endOfDay(Calendar calendar, Date date) {
299            calendar.setTime(date);
300            endOfDay(calendar);
301            return calendar.getTime();
302        }
303    
304    
305        /**
306         * Adjust the given calendar to the first millisecond of the current day.
307         * that is all time fields cleared.
308         * 
309         * @param calendar calendar to adjust.
310         */
311        public static void startOfDay(Calendar calendar) {
312            calendar.set(Calendar.HOUR_OF_DAY, 0);
313            calendar.set(Calendar.MILLISECOND, 0);
314            calendar.set(Calendar.SECOND, 0);
315            calendar.set(Calendar.MINUTE, 0);
316        }
317        /**
318         * Adjust the given calendar to the last millisecond of the specified date.
319         * 
320         * @param calendar calendar to adjust.
321         */
322        public static void endOfDay(Calendar calendar) {
323            calendar.add(Calendar.DATE, 1);
324            startOfDay(calendar);
325            calendar.add(Calendar.MILLISECOND, -1);
326        }
327    
328        /**
329         * Checks the given dates for being equal.
330         * 
331         * @param current one of the dates to compare
332         * @param date the otherr of the dates to compare
333         * @return true if the two given dates both are null or both are not null and equal, 
334         *  false otherwise.
335         */
336        public static boolean areEqual(Date current, Date date) {
337            if ((date == null) && (current == null)) {
338                return true;
339            }
340            if (date != null) {
341               return date.equals(current);
342            }
343            return false;
344        }
345    
346        /**
347         * Returns a boolean indicating whether the given Date is the same day as
348         * the day in the calendar. Calendar and date are unchanged by the check.
349         *
350         * @param today the Calendar representing a date, must not be null.
351         * @param now the date to compare to, must not be null
352         * @return true if the calendar and date represent the same day in the
353         *   given calendar.
354         */
355        public static boolean isSameDay(Calendar today, Date now) {
356            Calendar temp = (Calendar) today.clone();
357            startOfDay(temp);
358            Date start = temp.getTime();
359            temp.setTime(now);
360            startOfDay(temp);
361            return start.equals(temp.getTime());
362        }
363    
364    
365    }