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 */
021package org.jdesktop.swingx.calendar;
022
023import java.util.Calendar;
024import 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 */
039public 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}