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 006package fc.util; 007 008import java.util.*; 009import java.text.*; 010import java.util.concurrent.*; 011 012public final class CalendarUtil 013{ 014private static final boolean debug = false; 015 016public 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) */ 055public static final long ONE_SEC = 1000; 056 057/** Useful constant of 1 minute (in milliseconds) */ 058public static final long ONE_MIN = 1 * 60 * 1000; 059 060/** Useful constant of 2 minutes (in milliseconds) */ 061public static final long TWO_MIN = 2 * 60 * 1000; 062 063/** Useful constant of five minutes (in milliseconds) */ 064public static final long FIVE_MIN = 5 * 60 * 1000; 065 066/** Useful constant of ten minutes (in milliseconds) */ 067public static final long TEN_MIN = 10 * 60 * 1000; 068 069/** Useful constant of thirty minutes (in milliseconds) */ 070public static final long THIRTY_MIN = 30 * 60 * 1000; 071 072/** Useful constant of one hour (in milliseconds) */ 073public static final long ONE_HOUR = 60 * ONE_MIN; 074 075/** Useful constant of two hours (in milliseconds) */ 076public static final long TWO_HOUR = 2 * ONE_HOUR; 077 078/** Useful constant of four hours (in milliseconds) */ 079public static final long FOUR_HOUR = 4 * ONE_HOUR; 080 081/** Useful constant of eight hours (in milliseconds) */ 082public static final long EIGHT_HOUR = 8 * ONE_HOUR; 083 084/** Useful constant of twelve hours (in milliseconds) */ 085public static final long TWELVE_HOUR = 12 * ONE_HOUR; 086 087/** Useful constant of twenty four hours (in milliseconds) */ 088public static final long TWENTY_FOUR_HOUR = 24 * ONE_HOUR; 089 090/** Useful constant of 1 day (in milliseconds) */ 091public static final long ONE_DAY = TWENTY_FOUR_HOUR; 092 093/** Useful constant of 3 days (in milliseconds) */ 094public static final long THREE_DAY = 3 * ONE_DAY; 095 096/** Useful constant of 1 week (in milliseconds) */ 097public static final long ONE_WEEK = 7 * ONE_DAY; 098 099/** Useful constant of 2 weeks (in milliseconds) */ 100public static final long TWO_WEEK = 14 * ONE_DAY; 101 102/** Useful constant of 1 month (in milliseconds) [30 day month] */ 103public static final long ONE_MONTH = 30 * ONE_DAY; 104 105/** Useful constant of 2 months (in milliseconds) [30 day month] */ 106public static final long TWO_MONTH = 60 * ONE_DAY; 107 108/** Useful constant of 3 months (in milliseconds)[30 day month] */ 109public static final long THREE_MONTH = 90 * ONE_DAY; 110 111/** Useful constant of 6 months (in milliseconds) [30 day month] */ 112public static final long SIX_MONTH = 180 * ONE_DAY; 113 114/** Useful constant of one year (in milliseconds) [365 days]*/ 115public static final long ONE_YEAR = 365 * ONE_DAY; 116 117/** 118Sets the month in the specified calendar based on the specified 0-based 119month number. There is no direct setMonth method in Calendar. Therefore, 120this 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*/ 131public 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/** 154Returns the date representing the addition/subtraction of a number of hours from the specified 155starting timestamp. Specify a positive number for future/adding hours or negative for 156past/subtracing hours. 157<p> 158The state of the calendar is not affected by the calculations performed by this method. 159*/ 160public 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/** 173Returns 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> 175For example, any date with time component <tt>12.30pm</tt> returns the same date with a time component <tt>12.00pm</tt>. 176*/ 177public 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/** 195Returns the closest hour, starting from the current time and the specified calendar. 196The state of the calendar is not affected by the calculations performed by this 197method. 198<p> 199For example, any date with time component <tt>12.30pm</tt> returns the same date with a time component <tt>12.00pm</tt>. 200*/ 201public static Date getBeginOfCurrentHour(Calendar cal) 202 { 203 return getBeginOfHour(cal, new Date()); 204 } 205 206 207/** 208Returns 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> 210For example, any date with time component <tt>12.30pm</tt> returns the same date with a time component <tt>1.00pm</tt>. 211*/ 212public 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/** 229Returns 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> 231For example, any date with time component <tt>12.30pm</tt> returns the same date with a time component <tt>1.00pm</tt>. 232*/ 233public static Date getEndOfCurrentHour(Calendar cal) 234 { 235 return getEndOfHour(cal, new Date()); 236 } 237 238/** 239Returns the date representing the beginning of the specified day (at 24012:00:00.000 AM), starting from the current time and the specified calendar. 241The state of the calendar is not affected by the calculations performed by this 242method. 243*/ 244public 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/** 260Returns the date representing the beginning of the current day (at 12:00:00.000 261AM), starting from the current time and the specified calendar. The state of 262the calendar is not affected by the calculations performed by this method. 263*/ 264public static Date getBeginOfCurrentDay(Calendar cal) 265 { 266 return getBeginOfDay(cal, new Date()); 267 } 268 269/** 270Returns the date representing the end of the specified day (11:59:59.999 PM), 271starting from the current time and the specified calendar. The state of the 272calendar is not affected by the calculations performed by this method. 273*/ 274public 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/** 289Returns the date representing the end of the current day (11:59:59.999 PM), 290starting from the current time and the specified calendar. The state of the 291calendar is not affected by the calculations performed by this method. 292*/ 293public static Date getEndOfCurrentDay(Calendar cal) 294 { 295 return getEndOfDay(cal, new Date()); 296 } 297 298/** 299Returns the date representing the first day of the week (at 12:00:00.000 AM), 300using the specified date as the starting point of the week under consideration 301and the specified calendar. The state of the calendar is not affected by the 302calculations performed by this method. 303<p> 304The first day of week can vary based on the locale associated with the specified 305calendar (sunday in us, monday in fr, etc). 306*/ 307public 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/** 324Returns the date representing first day of the week (at 12:00:00.000 AM), starting 325from the current time and the specified calendar. The state of the calendar is 326not affected by the calculations performed by this method. 327*/ 328public static Date getFirstDayOfCurrentWeek(Calendar cal) 329 { 330 return getFirstDayOfWeek(cal, new Date()); 331 } 332 333/** 334Returns the date representing the last day of the week (at 11:59:59.999 PM) 335using the specified date as the starting point of the week under consideration 336and the specified calendar. The state of the calendar is not affected by the 337calculations performed by this method. 338<p> 339The last day of week can vary based on the locale associated with the specified 340calendar (saturday in us, sunday in fr, etc). 341*/ 342public 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/** 359Returns the date representing the last day of the week (11:59:59.999 PM), starting from the current 360time and the specified calendar. The state of the calendar is not affected by 361the calculations performed by this method. 362*/ 363public static Date getLastDayOfCurrentWeek(Calendar cal) 364 { 365 return getLastDayOfWeek(cal, new Date()); 366 } 367 368/** 369Returns the first day of the specified month with the default locale; 370*/ 371public 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/** 378Returns the first day of the current month with the default locale; 379*/ 380public static Date getFirstDayOfCurrentMonth(Calendar cal) 381 { 382 return getFirstDayOfMonth(cal, new Date()); 383 } 384 385/** 386Returns the last day of the specified month with the default locale; 387*/ 388public 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/** 395Returns the last day of the current month with the default locale; 396*/ 397public static Date getLastDayOfCurrentMonth(Calendar cal) 398 { 399 return getLastDayOfMonth(cal, new Date()); 400 } 401 402/** 403Returns {#getLastNMonths} with the default locale; 404*/ 405public static List getLastNMonths(Calendar cal, int nummonths) 406 { 407 return getLastNMonths(cal, new Date(), nummonths, Locale.getDefault()); 408 } 409 410/** 411Returns a List of Date[][], with each item being a month. The nummonths is the number 412of months to return and the startingDate is the starting month, to count backwards 413from. 414<p> 415In 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 416month and each successive item is the prior month. 417<p> 418For example: To get last 6 months, say: <tt>getLastNMonths(cal, today, 6)</tt> where 419cal is a calendar to use and today is today's date. 420*/ 421public 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/** 472returns true if the specified time is within the specified days, starting from 473the current time. 474*/ 475public static boolean withinLastNDays(long time, int n_days) 476 { 477 return System.currentTimeMillis() - time <= n_days * CalendarUtil.ONE_DAY; 478 } 479 480/** 481returns true if the specified time is within the specified days, starting from 482the current time. 483*/ 484public static boolean withinLastNDays(Date time, int n_days) 485 { 486 return System.currentTimeMillis() - time.getTime() <= n_days * CalendarUtil.ONE_DAY; 487 } 488 489/** 490returns true if the specified time is within the specified hours, starting from 491the current time. 492*/ 493public static boolean withinLastNHours(long time, int n_hours) 494 { 495 return System.currentTimeMillis() - time <= n_hours * CalendarUtil.ONE_HOUR; 496 } 497 498/** 499returns true if the specified time is within the specified hours, starting from 500the current time. 501*/ 502public static boolean withinLastNHours(Date time, int n_hours) 503 { 504 return System.currentTimeMillis() - time.getTime() <= n_hours * CalendarUtil.ONE_HOUR; 505 } 506 507 508/** 509returns true if the specified time is within the specified min, starting from 510the current time. 511*/ 512public static boolean withinLastNMin(Date time, int n_min) 513 { 514 return System.currentTimeMillis() - time.getTime() <= n_min * CalendarUtil.ONE_MIN; 515 } 516 517 518/** 519returns true if the specified time is within the specified seconds, starting from 520the current time. 521*/ 522public static boolean withinLastNSeconds(Date time, int n_seconds) 523 { 524 return System.currentTimeMillis() - time.getTime() <= n_seconds * 1000; 525 } 526 527 528/** 529returns the number of millis in the specified number of days 530*/ 531public static long daysToMillis(int days) 532 { 533 return days * CalendarUtil.ONE_DAY; 534 } 535 536/** 537returns the number of millis in the specified number of hours 538*/ 539public static long hoursToMillis(int hours) 540 { 541 return hours * CalendarUtil.ONE_HOUR; 542 } 543 544/** 545returns the number of millis in the specified hours 546*/ 547public static long minutesToMillis(int minutes) 548 { 549 return minutes * CalendarUtil.ONE_MIN; 550 } 551 552 553/** 554returns number of hours between begin and end timestamps. the 555order of begin/end is irrelevant, uses absolute value of difference 556between the two for the calculation. 557*/ 558public 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/** 565returns now as java.sql.Timestamp 566*/ 567public static java.sql.Timestamp getNowTimestamp() 568 { 569 return new java.sql.Timestamp(System.currentTimeMillis()); 570 } 571 572/** 573returns now as java.sql.Timestamp 574*/ 575public static java.sql.Timestamp now() 576 { 577 return getNowTimestamp(); 578 } 579 580public 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