001 // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org)
002 // The Molly framework is freely distributable under the terms of an
003 // MIT-style license. For details, see the molly pages web site at:
004 // http://www.mollypages.org/. Use, modify, have fun !
005
006 package fc.util;
007
008 import java.util.*;
009 import java.text.*;
010 import java.util.concurrent.*;
011
012 public final class CalendarUtil
013 {
014 private static final boolean debug = false;
015
016 public static enum Duration
017 {
018 HOURLY,
019 DAILY,
020 WEEKLY,
021 MONTHLY;
022
023 /**
024 Returns the date representing start time + duration. Uses the default
025 calendar instance internally.
026 */
027 public static Date getDateAfterDuration(Date start, Duration duration)
028 {
029 Calendar cal = Calendar.getInstance();
030
031 Date endDate = null;
032
033 switch (duration) {
034 case HOURLY:
035 endDate = CalendarUtil.getEndOfHour(cal, start);
036 break;
037 case DAILY:
038 endDate = CalendarUtil.getEndOfDay(cal, start);
039 break;
040 case WEEKLY:
041 endDate = CalendarUtil.getLastDayOfWeek(cal, start);
042 break;
043 case MONTHLY:
044 endDate = CalendarUtil.getLastDayOfMonth(cal, start);
045 break;
046 default:
047 throw new IllegalArgumentException("Don't know how to handle this duration");
048 }
049
050 return endDate;
051 }
052 }
053
054 /** Useful constant of 1 second (in milliseconds) */
055 public static final long ONE_SEC = 1000;
056
057 /** Useful constant of 1 minute (in milliseconds) */
058 public static final long ONE_MIN = 1 * 60 * 1000;
059
060 /** Useful constant of 2 minutes (in milliseconds) */
061 public static final long TWO_MIN = 2 * 60 * 1000;
062
063 /** Useful constant of five minutes (in milliseconds) */
064 public static final long FIVE_MIN = 5 * 60 * 1000;
065
066 /** Useful constant of ten minutes (in milliseconds) */
067 public static final long TEN_MIN = 10 * 60 * 1000;
068
069 /** Useful constant of thirty minutes (in milliseconds) */
070 public static final long THIRTY_MIN = 30 * 60 * 1000;
071
072 /** Useful constant of one hour (in milliseconds) */
073 public static final long ONE_HOUR = 60 * ONE_MIN;
074
075 /** Useful constant of two hours (in milliseconds) */
076 public static final long TWO_HOUR = 2 * ONE_HOUR;
077
078 /** Useful constant of four hours (in milliseconds) */
079 public static final long FOUR_HOUR = 4 * ONE_HOUR;
080
081 /** Useful constant of eight hours (in milliseconds) */
082 public static final long EIGHT_HOUR = 8 * ONE_HOUR;
083
084 /** Useful constant of twelve hours (in milliseconds) */
085 public static final long TWELVE_HOUR = 12 * ONE_HOUR;
086
087 /** Useful constant of twenty four hours (in milliseconds) */
088 public static final long TWENTY_FOUR_HOUR = 24 * ONE_HOUR;
089
090 /** Useful constant of 1 day (in milliseconds) */
091 public static final long ONE_DAY = TWENTY_FOUR_HOUR;
092
093 /** Useful constant of 3 days (in milliseconds) */
094 public static final long THREE_DAY = 3 * ONE_DAY;
095
096 /** Useful constant of 1 week (in milliseconds) */
097 public static final long ONE_WEEK = 7 * ONE_DAY;
098
099 /** Useful constant of 2 weeks (in milliseconds) */
100 public static final long TWO_WEEK = 14 * ONE_DAY;
101
102 /** Useful constant of 1 month (in milliseconds) [30 day month] */
103 public static final long ONE_MONTH = 30 * ONE_DAY;
104
105 /** Useful constant of 2 months (in milliseconds) [30 day month] */
106 public static final long TWO_MONTH = 60 * ONE_DAY;
107
108 /** Useful constant of 3 months (in milliseconds)[30 day month] */
109 public static final long THREE_MONTH = 90 * ONE_DAY;
110
111 /** Useful constant of 6 months (in milliseconds) [30 day month] */
112 public static final long SIX_MONTH = 180 * ONE_DAY;
113
114 /** Useful constant of one year (in milliseconds) [365 days]*/
115 public static final long ONE_YEAR = 365 * ONE_DAY;
116
117 /**
118 Sets the month in the specified calendar based on the specified 0-based
119 month number. There is no direct setMonth method in Calendar. Therefore,
120 this method is essentially a giant switch statement, like:
121 <blockquote><pre>
122 case 0:
123 cal.set(Calendar.MONTH, Calendar.JANUARY);
124 break;
125 case 1:
126 cal.set(Calendar.MONTH, Calendar.FEBRUARY);
127 break;
128 ... etc...
129 </pre></blockquote>
130 */
131 public static final void setMonth(Calendar cal, int monthNum)
132 { // 0-based
133 switch (monthNum)
134 {
135 case 0: cal.set(Calendar.MONTH, Calendar.JANUARY); break;
136 case 1: cal.set(Calendar.MONTH, Calendar.FEBRUARY); break;
137 case 2: cal.set(Calendar.MONTH, Calendar.MARCH); break;
138 case 3: cal.set(Calendar.MONTH, Calendar.APRIL); break;
139 case 4: cal.set(Calendar.MONTH, Calendar.MAY); break;
140 case 5: cal.set(Calendar.MONTH, Calendar.JUNE); break;
141 case 6: cal.set(Calendar.MONTH, Calendar.JULY); break;
142 case 7: cal.set(Calendar.MONTH, Calendar.AUGUST); break;
143 case 8: cal.set(Calendar.MONTH, Calendar.SEPTEMBER); break;
144 case 9: cal.set(Calendar.MONTH, Calendar.OCTOBER); break;
145 case 10: cal.set(Calendar.MONTH, Calendar.NOVEMBER); break;
146 case 11: cal.set(Calendar.MONTH, Calendar.DECEMBER); break;
147 default:
148 throw new RuntimeException("Month value out of range [" + monthNum + "]");
149 }
150 }
151
152
153 /**
154 Returns the date representing the addition/subtraction of a number of hours from the specified
155 starting timestamp. Specify a positive number for future/adding hours or negative for
156 past/subtracing hours.
157 <p>
158 The state of the calendar is not affected by the calculations performed by this method.
159 */
160 public static Date addHours(Calendar cal, Date d, int hours)
161 {
162 cal = (Calendar) cal.clone(); //don't affect underlying calendar
163
164 cal.setTime(d);
165
166 cal.add(Calendar.HOUR_OF_DAY, hours);
167
168 return cal.getTime();
169 }
170
171
172 /**
173 Returns the closest hour, starting from the specified time and the specified calendar. The state of the calendar is not affected by the calculations performed by this method.
174 <p>
175 For example, any date with time component <tt>12.30pm</tt> returns the same date with a time component <tt>12.00pm</tt>.
176 */
177 public static Date getBeginOfHour(Calendar cal, Date d)
178 {
179 cal = (Calendar) cal.clone(); //don't affect underlying calendar
180
181 cal.setTime(d);
182
183 //don't have to do anything with hour of day, we keep that hour
184 //cal.roll(Calendar.HOUR_OF_DAY, -1);
185
186 cal.clear(Calendar.MINUTE);
187 cal.clear(Calendar.SECOND);
188 cal.clear(Calendar.MILLISECOND);
189
190 return cal.getTime();
191 }
192
193
194 /**
195 Returns the closest hour, starting from the current time and the specified calendar.
196 The state of the calendar is not affected by the calculations performed by this
197 method.
198 <p>
199 For example, any date with time component <tt>12.30pm</tt> returns the same date with a time component <tt>12.00pm</tt>.
200 */
201 public static Date getBeginOfCurrentHour(Calendar cal)
202 {
203 return getBeginOfHour(cal, new Date());
204 }
205
206
207 /**
208 Returns the end of the hour, starting from the specified time and the specified calendar. The state of the calendar is not affected by the calculations performed by this method.
209 <p>
210 For example, any date with time component <tt>12.30pm</tt> returns the same date with a time component <tt>1.00pm</tt>.
211 */
212 public static Date getEndOfHour(Calendar cal, Date d)
213 {
214 cal = (Calendar) cal.clone(); //don't affect underlying calendar
215
216 cal.setTime(d);
217
218 cal.roll(Calendar.HOUR_OF_DAY, 1);
219
220 cal.clear(Calendar.MINUTE);
221 cal.clear(Calendar.SECOND);
222 cal.clear(Calendar.MILLISECOND);
223
224 return cal.getTime();
225 }
226
227
228 /**
229 Returns the end of the hour, starting from the current time and the specified calendar. The state of the calendar is not affected by the calculations performed by this method.
230 <p>
231 For example, any date with time component <tt>12.30pm</tt> returns the same date with a time component <tt>1.00pm</tt>.
232 */
233 public static Date getEndOfCurrentHour(Calendar cal)
234 {
235 return getEndOfHour(cal, new Date());
236 }
237
238 /**
239 Returns the date representing the beginning of the specified day (at
240 12:00:00.000 AM), starting from the current time and the specified calendar.
241 The state of the calendar is not affected by the calculations performed by this
242 method.
243 */
244 public static Date getBeginOfDay(Calendar cal, Date d)
245 {
246 cal = (Calendar) cal.clone(); //don't affect underlying calendar
247
248 cal.setTime(d);
249
250 cal.set(Calendar.HOUR_OF_DAY, 0);
251 cal.clear(Calendar.MINUTE);
252 cal.clear(Calendar.SECOND);
253 cal.clear(Calendar.MILLISECOND);
254
255 return cal.getTime();
256 }
257
258
259 /**
260 Returns the date representing the beginning of the current day (at 12:00:00.000
261 AM), starting from the current time and the specified calendar. The state of
262 the calendar is not affected by the calculations performed by this method.
263 */
264 public static Date getBeginOfCurrentDay(Calendar cal)
265 {
266 return getBeginOfDay(cal, new Date());
267 }
268
269 /**
270 Returns the date representing the end of the specified day (11:59:59.999 PM),
271 starting from the current time and the specified calendar. The state of the
272 calendar is not affected by the calculations performed by this method.
273 */
274 public static Date getEndOfDay(Calendar cal, Date d)
275 {
276 cal = (Calendar) cal.clone(); //don't affect underlying calendar
277
278 cal.setTime(d);
279
280 cal.set(Calendar.HOUR_OF_DAY, 23);
281 cal.set(Calendar.MINUTE, 59);
282 cal.set(Calendar.SECOND, 59);
283 cal.set(Calendar.MILLISECOND, 999);
284
285 return cal.getTime();
286 }
287
288 /**
289 Returns the date representing the end of the current day (11:59:59.999 PM),
290 starting from the current time and the specified calendar. The state of the
291 calendar is not affected by the calculations performed by this method.
292 */
293 public static Date getEndOfCurrentDay(Calendar cal)
294 {
295 return getEndOfDay(cal, new Date());
296 }
297
298 /**
299 Returns the date representing the first day of the week (at 12:00:00.000 AM),
300 using the specified date as the starting point of the week under consideration
301 and the specified calendar. The state of the calendar is not affected by the
302 calculations performed by this method.
303 <p>
304 The first day of week can vary based on the locale associated with the specified
305 calendar (sunday in us, monday in fr, etc).
306 */
307 public static Date getFirstDayOfWeek(Calendar cal, Date d)
308 {
309 cal = (Calendar) cal.clone(); //don't affect underlying calendar
310
311 cal.setTime(d);
312
313 cal.set(Calendar.HOUR_OF_DAY, 0);
314 cal.clear(Calendar.MINUTE);
315 cal.clear(Calendar.SECOND);
316 cal.clear(Calendar.MILLISECOND);
317
318 cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
319
320 return cal.getTime();
321 }
322
323 /**
324 Returns the date representing first day of the week (at 12:00:00.000 AM), starting
325 from the current time and the specified calendar. The state of the calendar is
326 not affected by the calculations performed by this method.
327 */
328 public static Date getFirstDayOfCurrentWeek(Calendar cal)
329 {
330 return getFirstDayOfWeek(cal, new Date());
331 }
332
333 /**
334 Returns the date representing the last day of the week (at 11:59:59.999 PM)
335 using the specified date as the starting point of the week under consideration
336 and the specified calendar. The state of the calendar is not affected by the
337 calculations performed by this method.
338 <p>
339 The last day of week can vary based on the locale associated with the specified
340 calendar (saturday in us, sunday in fr, etc).
341 */
342 public static Date getLastDayOfWeek(Calendar cal, Date d)
343 {
344 cal = (Calendar) cal.clone(); //don't affect underlying calendar
345
346 cal.setTime(d);
347
348 cal.set(Calendar.HOUR_OF_DAY, 23);
349 cal.set(Calendar.MINUTE, 59);
350 cal.set(Calendar.SECOND, 59);
351 cal.set(Calendar.MILLISECOND, 999);
352
353 cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek() + 6);
354
355 return cal.getTime();
356 }
357
358 /**
359 Returns the date representing the last day of the week (11:59:59.999 PM), starting from the current
360 time and the specified calendar. The state of the calendar is not affected by
361 the calculations performed by this method.
362 */
363 public static Date getLastDayOfCurrentWeek(Calendar cal)
364 {
365 return getLastDayOfWeek(cal, new Date());
366 }
367
368 /**
369 Returns the first day of the specified month with the default locale;
370 */
371 public static Date getFirstDayOfMonth(Calendar cal, Date d)
372 {
373 List list = getLastNMonths(cal, d, 1, Locale.getDefault());
374 return ((Date[])list.get(0))[0];
375 }
376
377 /**
378 Returns the first day of the current month with the default locale;
379 */
380 public static Date getFirstDayOfCurrentMonth(Calendar cal)
381 {
382 return getFirstDayOfMonth(cal, new Date());
383 }
384
385 /**
386 Returns the last day of the specified month with the default locale;
387 */
388 public static Date getLastDayOfMonth(Calendar cal, Date d)
389 {
390 List list = getLastNMonths(cal, d, 1, Locale.getDefault());
391 return ((Date[])list.get(0))[1];
392 }
393
394 /**
395 Returns the last day of the current month with the default locale;
396 */
397 public static Date getLastDayOfCurrentMonth(Calendar cal)
398 {
399 return getLastDayOfMonth(cal, new Date());
400 }
401
402 /**
403 Returns {#getLastNMonths} with the default locale;
404 */
405 public static List getLastNMonths(Calendar cal, int nummonths)
406 {
407 return getLastNMonths(cal, new Date(), nummonths, Locale.getDefault());
408 }
409
410 /**
411 Returns a List of Date[][], with each item being a month. The nummonths is the number
412 of months to return and the startingDate is the starting month, to count backwards
413 from.
414 <p>
415 In the returned list, date[0] represents the first day, 12:00:00.000 AM and date[1] representing the last day, 11:59:59.999 PM. The starting item in the list is the nearest
416 month and each successive item is the prior month.
417 <p>
418 For example: To get last 6 months, say: <tt>getLastNMonths(cal, today, 6)</tt> where
419 cal is a calendar to use and today is today's date.
420 */
421 public static List getLastNMonths(Calendar cal, Date startingDate, int nummonths, Locale locale)
422 {
423 DateFormatSymbols dfs = new DateFormatSymbols(locale);
424 String[] monthnames_short = dfs.getShortMonths();
425
426 cal = (Calendar) cal.clone(); //don't affect underlying calendar
427
428 cal.setTime(startingDate);
429
430 if (debug) System.out.println("Current Month (0 based): " + cal.get(Calendar.MONTH));
431
432 List list = new ArrayList();
433 for (int n = 0; n < nummonths; n++)
434 {
435 int month = cal.get(Calendar.MONTH);
436
437 int days_in_month = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
438 if (debug) System.out.println("number of days in month: " + days_in_month);
439
440 Date[] dates = new Date[2];
441
442 //date[0], start of month
443 cal.set(Calendar.DAY_OF_MONTH, 1);
444
445 cal.set(Calendar.HOUR_OF_DAY, 0);
446 cal.clear(Calendar.MINUTE);
447 cal.clear(Calendar.SECOND);
448 cal.clear(Calendar.MILLISECOND);
449
450 dates[0] = cal.getTime();
451
452 //date[1], end of month
453 cal.set(Calendar.DAY_OF_MONTH, days_in_month);
454
455 cal.set(Calendar.HOUR_OF_DAY, 23);
456 cal.set(Calendar.MINUTE, 59);
457 cal.set(Calendar.SECOND, 59);
458 cal.set(Calendar.MILLISECOND, 999);
459
460 dates[1] = cal.getTime();
461 list.add(dates);
462
463 cal.roll(Calendar.MONTH, -1);
464 }
465
466 return list;
467 }
468
469 //#mark -- other misc --
470
471 /**
472 returns true if the specified time is within the specified days, starting from
473 the current time.
474 */
475 public static boolean withinLastNDays(long time, int n_days)
476 {
477 return System.currentTimeMillis() - time <= n_days * CalendarUtil.ONE_DAY;
478 }
479
480 /**
481 returns true if the specified time is within the specified days, starting from
482 the current time.
483 */
484 public static boolean withinLastNDays(Date time, int n_days)
485 {
486 return System.currentTimeMillis() - time.getTime() <= n_days * CalendarUtil.ONE_DAY;
487 }
488
489 /**
490 returns true if the specified time is within the specified hours, starting from
491 the current time.
492 */
493 public static boolean withinLastNHours(long time, int n_hours)
494 {
495 return System.currentTimeMillis() - time <= n_hours * CalendarUtil.ONE_HOUR;
496 }
497
498 /**
499 returns true if the specified time is within the specified hours, starting from
500 the current time.
501 */
502 public static boolean withinLastNHours(Date time, int n_hours)
503 {
504 return System.currentTimeMillis() - time.getTime() <= n_hours * CalendarUtil.ONE_HOUR;
505 }
506
507
508 /**
509 returns true if the specified time is within the specified min, starting from
510 the current time.
511 */
512 public static boolean withinLastNMin(Date time, int n_min)
513 {
514 return System.currentTimeMillis() - time.getTime() <= n_min * CalendarUtil.ONE_MIN;
515 }
516
517
518 /**
519 returns true if the specified time is within the specified seconds, starting from
520 the current time.
521 */
522 public static boolean withinLastNSeconds(Date time, int n_seconds)
523 {
524 return System.currentTimeMillis() - time.getTime() <= n_seconds * 1000;
525 }
526
527
528 /**
529 returns the number of millis in the specified number of days
530 */
531 public static long daysToMillis(int days)
532 {
533 return days * CalendarUtil.ONE_DAY;
534 }
535
536 /**
537 returns the number of millis in the specified number of hours
538 */
539 public static long hoursToMillis(int hours)
540 {
541 return hours * CalendarUtil.ONE_HOUR;
542 }
543
544 /**
545 returns the number of millis in the specified hours
546 */
547 public static long minutesToMillis(int minutes)
548 {
549 return minutes * CalendarUtil.ONE_MIN;
550 }
551
552
553 /**
554 returns number of hours between begin and end timestamps. the
555 order of begin/end is irrelevant, uses absolute value of difference
556 between the two for the calculation.
557 */
558 public static int hoursBetween(Date begin, Date end)
559 {
560 final long diff = Math.abs(begin.getTime() - end.getTime());
561 return (int) TimeUnit.HOURS.convert(diff, TimeUnit.MILLISECONDS);
562 }
563
564 /**
565 returns now as java.sql.Timestamp
566 */
567 public static java.sql.Timestamp getNowTimestamp()
568 {
569 return new java.sql.Timestamp(System.currentTimeMillis());
570 }
571
572 /**
573 returns now as java.sql.Timestamp
574 */
575 public static java.sql.Timestamp now()
576 {
577 return getNowTimestamp();
578 }
579
580 public static void main (String args[]) throws Exception
581 {
582 Args myargs = new Args(args);
583 ToString.Style style = new ToString.Style();
584 style.reflectStatics = true;
585 System.out.println(
586 new ToString(new CalendarUtil(), style).reflect().render());
587
588 Calendar cal = Calendar.getInstance();
589 Date d = new Date();
590 if (myargs.flagExists("date")) {
591 d = DateFormat.getDateInstance(DateFormat.SHORT)
592 .parse(myargs.get("date"));
593 }
594
595 System.out.println("========== hour =========");
596 System.out.println("beginOfHour: " + getBeginOfHour(cal, d));
597 System.out.println("endOfHour: " + getEndOfHour(cal, d));
598 System.out.println("beginOfCurrentHour: " + getBeginOfCurrentHour(cal));
599 System.out.println("endOfCurrentHour: " + getEndOfCurrentHour(cal));
600
601 System.out.println("========== day =========");
602 System.out.println("beginOfDay: " + getBeginOfDay(cal, d));
603 System.out.println("endOfDay: " + getEndOfDay(cal, d));
604 System.out.println("beginOfCurrentDay: " + getBeginOfCurrentDay(cal));
605 System.out.println("endOfCurrentDay: " + getEndOfCurrentDay(cal));
606
607 System.out.println("========== week =========");
608 System.out.println("firstDayOfWeek: " + getFirstDayOfWeek(cal, d));
609 System.out.println("lastDayOfWeek: " + getLastDayOfWeek(cal, d));
610 System.out.println("firstDayOfCurrentWeek: " + getFirstDayOfCurrentWeek(cal));
611 System.out.println("lastDayOfCurrentWeek: " + getLastDayOfCurrentWeek(cal));
612
613 System.out.println("========== month =========");
614 System.out.println("firstDayOfMonth: " + getFirstDayOfMonth(cal,d));
615 System.out.println("lastDayOfMonth: " + getLastDayOfMonth(cal,d));
616 System.out.println("firstDayOfCurrentMonth: " + getFirstDayOfCurrentMonth(cal));
617 System.out.println("lastDayOfCurrentMonth: " + getLastDayOfCurrentMonth(cal));
618
619 System.out.println("==== lastNMonths(6) ======");
620 System.out.println(Arrays.deepToString(getLastNMonths(cal, d, 6, Locale.getDefault()).toArray()));
621 }
622 }
623