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