001    /*
002     * $Id: DateUtils.java 3100 2008-10-14 22:33:10Z rah003 $
003     *
004     * Copyright 2004 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     * Utility methods for Date manipulation. <p>
028     * 
029     * This utility class is replaced by CalendarUtils because day related manipulation
030     * are meaningfull relative to a Calendar only. Always doing so against the default
031     * calendar instance isn't enough.
032     * 
033     * PENDING JW: move the missing ops. Volunteers, please! Once done, this will be deprecated.
034     * 
035     * @author Scott Violet
036     * @version  $Revision: 3100 $
037     * 
038     */
039    public class DateUtils {
040        private static Calendar CALENDAR = Calendar.getInstance();
041    
042        /**
043         * Returns the last millisecond of the specified date.
044         *
045         * @param date Date to calculate end of day from
046         * @return Last millisecond of <code>date</code>
047         */
048        public static Date endOfDay(Date date) {
049            Calendar calendar = CALENDAR;
050            synchronized(calendar) {
051                calendar.setTime(date);
052                calendar.set(Calendar.HOUR_OF_DAY, 23);
053                calendar.set(Calendar.MILLISECOND, 999);
054                calendar.set(Calendar.SECOND, 59);
055                calendar.set(Calendar.MINUTE, 59);
056                return calendar.getTime();
057            }
058        }
059    
060    
061        /**
062         * Returns a new Date with the hours, milliseconds, seconds and minutes
063         * set to 0.
064         *
065         * @param date Date used in calculating start of day
066         * @return Start of <code>date</code>
067         */
068        public static Date startOfDay(Date date) {
069            Calendar calendar = CALENDAR;
070            synchronized(calendar) {
071                calendar.setTime(date);
072                calendar.set(Calendar.HOUR_OF_DAY, 0);
073                calendar.set(Calendar.MILLISECOND, 0);
074                calendar.set(Calendar.SECOND, 0);
075                calendar.set(Calendar.MINUTE, 0);
076                return calendar.getTime();
077            }
078        }
079    
080         /**
081         * Returns day in millis with the hours, milliseconds, seconds and minutes
082         * set to 0.
083         *
084         * @param date long used in calculating start of day
085         * @return Start of <code>date</code>
086         */
087        public static long startOfDayInMillis(long date) {
088            Calendar calendar = CALENDAR;
089            synchronized(calendar) {
090                calendar.setTimeInMillis(date);
091                calendar.set(Calendar.HOUR_OF_DAY, 0);
092                calendar.set(Calendar.MILLISECOND, 0);
093                calendar.set(Calendar.SECOND, 0);
094                calendar.set(Calendar.MINUTE, 0);
095                return calendar.getTimeInMillis();
096            }
097        }
098    
099        /**
100         * Returns the last millisecond of the specified date.
101         *
102         * @param date long to calculate end of day from
103         * @return Last millisecond of <code>date</code>
104         */
105        public static long endOfDayInMillis(long date) {
106            Calendar calendar = CALENDAR;
107            synchronized(calendar) {
108                calendar.setTimeInMillis(date);
109                calendar.set(Calendar.HOUR_OF_DAY, 23);
110                calendar.set(Calendar.MILLISECOND, 999);
111                calendar.set(Calendar.SECOND, 59);
112                calendar.set(Calendar.MINUTE, 59);
113                return calendar.getTimeInMillis();
114            }
115        }
116    
117    
118        /**
119         * Returns the day after <code>date</code>.
120         *
121         * @param date Date used in calculating next day
122         * @return Day after <code>date</code>.
123         */
124        public static Date nextDay(Date date) {
125            return new Date(addDays(date.getTime(), 1));
126        }
127    
128        /**
129         * Adds <code>amount</code> days to <code>time</code> and returns
130         * the resulting time.
131         *
132         * @param time Base time
133         * @param amount Amount of increment.
134         * 
135         * @return the <var>time</var> + <var>amount</var> days
136         */
137        public static long addDays(long time, int amount) {
138            Calendar calendar = CALENDAR;
139            synchronized(calendar) {
140                calendar.setTimeInMillis(time);
141                calendar.add(Calendar.DAY_OF_MONTH, amount);
142                return calendar.getTimeInMillis();
143            }
144        }
145    
146        /**
147         * Returns the day after <code>date</code>.
148         *
149         * @param date Date used in calculating next day
150         * @return Day after <code>date</code>.
151         */
152        public static long nextDay(long date) {
153            return addDays(date, 1);
154        }
155    
156        /**
157         * Returns the week after <code>date</code>.
158         *
159         * @param date Date used in calculating next week
160         * @return week after <code>date</code>.
161         */
162        public static long nextWeek(long date) {
163            return addDays(date, 7);
164        }
165    
166    
167        /**
168         * Returns the number of days difference between <code>t1</code> and
169         * <code>t2</code>.
170         *
171         * @param t1 Time 1
172         * @param t2 Time 2
173         * @param checkOverflow indicates whether to check for overflow
174         * @return Number of days between <code>start</code> and <code>end</code>
175         */
176        public static int getDaysDiff(long t1, long t2, boolean checkOverflow) {
177            if (t1 > t2) {
178                long tmp = t1;
179                t1 = t2;
180                t2 = tmp;
181            }
182            Calendar calendar = CALENDAR;
183            synchronized(calendar) {
184                calendar.setTimeInMillis(t1);
185                int delta = 0;
186                while (calendar.getTimeInMillis() < t2) {
187                    calendar.add(Calendar.DAY_OF_MONTH, 1);
188                    delta++;
189                }
190                if (checkOverflow && (calendar.getTimeInMillis() > t2)) {
191                    delta--;
192                }
193                return delta;
194            }
195        }
196    
197       /**
198         * Returns the number of days difference between <code>t1</code> and
199         * <code>t2</code>.
200         *
201         * @param t1 Time 1
202         * @param t2 Time 2
203         * @return Number of days between <code>start</code> and <code>end</code>
204         */
205          public static int getDaysDiff(long t1, long t2) {
206           return  getDaysDiff(t1, t2, true);
207        }
208    
209        /**
210         * Check, whether the date passed in is the first day of the year.
211         *
212         * @param date date to check in millis
213         * @return <code>true</code> if <var>date</var> corresponds to the first
214         *         day of a year
215         * @see Date#getTime() 
216         */
217        public static boolean isFirstOfYear(long date) {
218            boolean ret = false;
219            Calendar calendar = CALENDAR;
220            synchronized(calendar) {
221                calendar.setTimeInMillis(date);
222                int currentYear = calendar.get(Calendar.YEAR);
223                // Check yesterday
224                calendar.add(Calendar.DATE,-1);
225                int yesterdayYear = calendar.get(Calendar.YEAR);
226                ret = (currentYear != yesterdayYear);
227            }
228            return ret;
229        }
230    
231        /**
232         * Check, whether the date passed in is the first day of the month.
233         *
234         * @param date date to check in millis
235         * @return <code>true</code> if <var>date</var> corresponds to the first
236         *         day of a month
237         * @see Date#getTime() 
238         */
239        public static boolean isFirstOfMonth(long date) {
240            boolean ret = false;
241            Calendar calendar = CALENDAR;
242            synchronized(calendar) {
243                calendar.setTimeInMillis(date);
244                int currentMonth = calendar.get(Calendar.MONTH);
245                // Check yesterday
246                calendar.add(Calendar.DATE,-1);
247                int yesterdayMonth = calendar.get(Calendar.MONTH);
248                ret =  (currentMonth != yesterdayMonth);
249            }
250            return ret;     
251        }
252    
253    
254        /**
255         * Returns the day before <code>date</code>.
256         *
257         * @param date Date used in calculating previous day
258         * @return Day before <code>date</code>.
259         */
260        public static long previousDay(long date) {
261            return addDays(date, -1);
262        }
263    
264        /**
265         * Returns the week before <code>date</code>.
266         *
267         * @param date Date used in calculating previous week
268         * @return week before <code>date</code>.
269         */
270        public static long previousWeek(long date) {
271            return addDays(date, -7);
272        }
273    
274    
275        /**
276         * Returns the first day before <code>date</code> that has the
277         * day of week matching <code>startOfWeek</code>.  For example, if you
278         * want to find the previous monday relative to <code>date</code> you
279         * would call <code>getPreviousDay(date, Calendar.MONDAY)</code>.
280         *
281         * @param date Base date
282         * @param startOfWeek Calendar constant correspoding to start of week.
283         * @return start of week, return value will have 0 hours, 0 minutes,
284         *         0 seconds and 0 ms.
285         * 
286         */
287        public static long getPreviousDay(long date, int startOfWeek) {
288            return getDay(date, startOfWeek, -1);
289        }
290    
291        /**
292         * Returns the first day after <code>date</code> that has the
293         * day of week matching <code>startOfWeek</code>.  For example, if you
294         * want to find the next monday relative to <code>date</code> you
295         * would call <code>getPreviousDay(date, Calendar.MONDAY)</code>.
296         *
297         * @param date Base date
298         * @param startOfWeek Calendar constant correspoding to start of week.
299         * @return start of week, return value will have 0 hours, 0 minutes,
300         *         0 seconds and 0 ms.
301         * 
302         */
303        public static long getNextDay(long date, int startOfWeek) {
304            return getDay(date, startOfWeek, 1);
305        }
306    
307        private static long getDay(long date, int startOfWeek, int increment) {
308            Calendar calendar = CALENDAR;
309            synchronized(calendar) {
310                calendar.setTimeInMillis(date);
311                int day = calendar.get(Calendar.DAY_OF_WEEK);
312                // Normalize the view starting date to a week starting day
313                while (day != startOfWeek) {
314                    calendar.add(Calendar.DATE, increment);
315                    day = calendar.get(Calendar.DAY_OF_WEEK);
316                }
317                return startOfDayInMillis(calendar.getTimeInMillis());
318            }
319        }
320    
321        /**
322         * Returns the previous month.
323         * 
324         * @param date Base date
325         * @return previous month
326         */
327        public static long getPreviousMonth(long date) {
328            return incrementMonth(date, -1);
329        }
330    
331        /**
332         * Returns the next month.
333         * 
334         * @param date Base date
335         * @return next month
336         */
337        public static long getNextMonth(long date) {
338            return incrementMonth(date, 1);
339        }
340    
341        private static long incrementMonth(long date, int increment) {
342            Calendar calendar = CALENDAR;
343            synchronized(calendar) {
344                calendar.setTimeInMillis(date);
345                calendar.add(Calendar.MONTH, increment);
346                return calendar.getTimeInMillis();
347            }
348        }
349    
350        /**
351         * Returns the date corresponding to the start of the month.
352         *
353         * @param date Base date
354         * @return Start of month.
355         */
356        public static long getStartOfMonth(long date) {
357            return getMonth(date, -1);
358        }
359    
360        /**
361         * Returns the date corresponding to the end of the month.
362         *
363         * @param date Base date
364         * @return End of month.
365         */
366        public static long getEndOfMonth(long date) {
367            return getMonth(date, 1);
368        }
369    
370        private static long getMonth(long date, int increment) {
371            long result;
372            Calendar calendar = CALENDAR;
373            synchronized(calendar) {
374                calendar.setTimeInMillis(date);
375                if (increment == -1) {
376                    calendar.set(Calendar.DAY_OF_MONTH, 1);
377                    result = startOfDayInMillis(calendar.getTimeInMillis());
378                } else {
379                    calendar.add(Calendar.MONTH, 1);
380                    calendar.set(Calendar.DAY_OF_MONTH, 1);
381                    calendar.set(Calendar.HOUR_OF_DAY, 0);
382                    calendar.set(Calendar.MILLISECOND, 0);
383                    calendar.set(Calendar.SECOND, 0);
384                    calendar.set(Calendar.MINUTE, 0);
385                    calendar.add(Calendar.MILLISECOND, -1);
386                    result = calendar.getTimeInMillis();
387                }
388            }
389            return result;
390        }
391    
392        /**
393         * Returns the day of the week.
394         *
395         * @param date date
396         * @return day of week.
397         */
398        public static int getDayOfWeek(long date) {
399           Calendar calendar = CALENDAR;
400            synchronized(calendar) {
401                calendar.setTimeInMillis(date);
402                return (calendar.get(Calendar.DAY_OF_WEEK));
403            }
404        }
405    }