001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.lang.time; 018 019 import java.text.ParseException; 020 import java.text.ParsePosition; 021 import java.text.SimpleDateFormat; 022 import java.util.Calendar; 023 import java.util.Date; 024 import java.util.Iterator; 025 import java.util.NoSuchElementException; 026 import java.util.TimeZone; 027 028 import org.apache.commons.lang.StringUtils; 029 030 /** 031 * <p>A suite of utilities surrounding the use of the 032 * {@link java.util.Calendar} and {@link java.util.Date} object.</p> 033 * 034 * <p>DateUtils contains a lot of common methods considering manipulations 035 * of Dates or Calendars. Some methods require some extra explanation. 036 * The truncate, ceiling and round methods could be considered the Math.floor(), 037 * Math.ceil() or Math.round versions for dates 038 * This way date-fields will be ignored in bottom-up order. 039 * As a complement to these methods we've introduced some fragment-methods. 040 * With these methods the Date-fields will be ignored in top-down order. 041 * Since a date without a year is not a valid date, you have to decide in what 042 * kind of date-field you want your result, for instance milliseconds or days. 043 * </p> 044 * 045 * 046 * 047 * @author Apache Software Foundation 048 * @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a> 049 * @author Janek Bogucki 050 * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a> 051 * @author Phil Steitz 052 * @author Robert Scholte 053 * @since 2.0 054 * @version $Id: DateUtils.java 911986 2010-02-19 21:19:05Z niallp $ 055 */ 056 public class DateUtils { 057 058 /** 059 * The UTC time zone (often referred to as GMT). 060 */ 061 public static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("GMT"); 062 /** 063 * Number of milliseconds in a standard second. 064 * @since 2.1 065 */ 066 public static final long MILLIS_PER_SECOND = 1000; 067 /** 068 * Number of milliseconds in a standard minute. 069 * @since 2.1 070 */ 071 public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; 072 /** 073 * Number of milliseconds in a standard hour. 074 * @since 2.1 075 */ 076 public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; 077 /** 078 * Number of milliseconds in a standard day. 079 * @since 2.1 080 */ 081 public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR; 082 083 /** 084 * This is half a month, so this represents whether a date is in the top 085 * or bottom half of the month. 086 */ 087 public final static int SEMI_MONTH = 1001; 088 089 private static final int[][] fields = { 090 {Calendar.MILLISECOND}, 091 {Calendar.SECOND}, 092 {Calendar.MINUTE}, 093 {Calendar.HOUR_OF_DAY, Calendar.HOUR}, 094 {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM 095 /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */ 096 }, 097 {Calendar.MONTH, DateUtils.SEMI_MONTH}, 098 {Calendar.YEAR}, 099 {Calendar.ERA}}; 100 101 /** 102 * A week range, starting on Sunday. 103 */ 104 public final static int RANGE_WEEK_SUNDAY = 1; 105 106 /** 107 * A week range, starting on Monday. 108 */ 109 public final static int RANGE_WEEK_MONDAY = 2; 110 111 /** 112 * A week range, starting on the day focused. 113 */ 114 public final static int RANGE_WEEK_RELATIVE = 3; 115 116 /** 117 * A week range, centered around the day focused. 118 */ 119 public final static int RANGE_WEEK_CENTER = 4; 120 121 /** 122 * A month range, the week starting on Sunday. 123 */ 124 public final static int RANGE_MONTH_SUNDAY = 5; 125 126 /** 127 * A month range, the week starting on Monday. 128 */ 129 public final static int RANGE_MONTH_MONDAY = 6; 130 131 /** 132 * Constant marker for truncating 133 */ 134 private final static int MODIFY_TRUNCATE = 0; 135 136 /** 137 * Constant marker for rounding 138 */ 139 private final static int MODIFY_ROUND = 1; 140 141 /** 142 * Constant marker for ceiling 143 */ 144 private final static int MODIFY_CEILING= 2; 145 146 /** 147 * <p><code>DateUtils</code> instances should NOT be constructed in 148 * standard programming. Instead, the class should be used as 149 * <code>DateUtils.parse(str);</code>.</p> 150 * 151 * <p>This constructor is public to permit tools that require a JavaBean 152 * instance to operate.</p> 153 */ 154 public DateUtils() { 155 super(); 156 } 157 158 //----------------------------------------------------------------------- 159 /** 160 * <p>Checks if two date objects are on the same day ignoring time.</p> 161 * 162 * <p>28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true. 163 * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false. 164 * </p> 165 * 166 * @param date1 the first date, not altered, not null 167 * @param date2 the second date, not altered, not null 168 * @return true if they represent the same day 169 * @throws IllegalArgumentException if either date is <code>null</code> 170 * @since 2.1 171 */ 172 public static boolean isSameDay(Date date1, Date date2) { 173 if (date1 == null || date2 == null) { 174 throw new IllegalArgumentException("The date must not be null"); 175 } 176 Calendar cal1 = Calendar.getInstance(); 177 cal1.setTime(date1); 178 Calendar cal2 = Calendar.getInstance(); 179 cal2.setTime(date2); 180 return isSameDay(cal1, cal2); 181 } 182 183 /** 184 * <p>Checks if two calendar objects are on the same day ignoring time.</p> 185 * 186 * <p>28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true. 187 * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false. 188 * </p> 189 * 190 * @param cal1 the first calendar, not altered, not null 191 * @param cal2 the second calendar, not altered, not null 192 * @return true if they represent the same day 193 * @throws IllegalArgumentException if either calendar is <code>null</code> 194 * @since 2.1 195 */ 196 public static boolean isSameDay(Calendar cal1, Calendar cal2) { 197 if (cal1 == null || cal2 == null) { 198 throw new IllegalArgumentException("The date must not be null"); 199 } 200 return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && 201 cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && 202 cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); 203 } 204 205 //----------------------------------------------------------------------- 206 /** 207 * <p>Checks if two date objects represent the same instant in time.</p> 208 * 209 * <p>This method compares the long millisecond time of the two objects.</p> 210 * 211 * @param date1 the first date, not altered, not null 212 * @param date2 the second date, not altered, not null 213 * @return true if they represent the same millisecond instant 214 * @throws IllegalArgumentException if either date is <code>null</code> 215 * @since 2.1 216 */ 217 public static boolean isSameInstant(Date date1, Date date2) { 218 if (date1 == null || date2 == null) { 219 throw new IllegalArgumentException("The date must not be null"); 220 } 221 return date1.getTime() == date2.getTime(); 222 } 223 224 /** 225 * <p>Checks if two calendar objects represent the same instant in time.</p> 226 * 227 * <p>This method compares the long millisecond time of the two objects.</p> 228 * 229 * @param cal1 the first calendar, not altered, not null 230 * @param cal2 the second calendar, not altered, not null 231 * @return true if they represent the same millisecond instant 232 * @throws IllegalArgumentException if either date is <code>null</code> 233 * @since 2.1 234 */ 235 public static boolean isSameInstant(Calendar cal1, Calendar cal2) { 236 if (cal1 == null || cal2 == null) { 237 throw new IllegalArgumentException("The date must not be null"); 238 } 239 return cal1.getTime().getTime() == cal2.getTime().getTime(); 240 } 241 242 //----------------------------------------------------------------------- 243 /** 244 * <p>Checks if two calendar objects represent the same local time.</p> 245 * 246 * <p>This method compares the values of the fields of the two objects. 247 * In addition, both calendars must be the same of the same type.</p> 248 * 249 * @param cal1 the first calendar, not altered, not null 250 * @param cal2 the second calendar, not altered, not null 251 * @return true if they represent the same millisecond instant 252 * @throws IllegalArgumentException if either date is <code>null</code> 253 * @since 2.1 254 */ 255 public static boolean isSameLocalTime(Calendar cal1, Calendar cal2) { 256 if (cal1 == null || cal2 == null) { 257 throw new IllegalArgumentException("The date must not be null"); 258 } 259 return (cal1.get(Calendar.MILLISECOND) == cal2.get(Calendar.MILLISECOND) && 260 cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND) && 261 cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE) && 262 cal1.get(Calendar.HOUR) == cal2.get(Calendar.HOUR) && 263 cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && 264 cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && 265 cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && 266 cal1.getClass() == cal2.getClass()); 267 } 268 269 //----------------------------------------------------------------------- 270 /** 271 * <p>Parses a string representing a date by trying a variety of different parsers.</p> 272 * 273 * <p>The parse will try each parse pattern in turn. 274 * A parse is only deemed successful if it parses the whole of the input string. 275 * If no parse patterns match, a ParseException is thrown.</p> 276 * The parser will be lenient toward the parsed date. 277 * 278 * @param str the date to parse, not null 279 * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null 280 * @return the parsed date 281 * @throws IllegalArgumentException if the date string or pattern array is null 282 * @throws ParseException if none of the date patterns were suitable (or there were none) 283 */ 284 public static Date parseDate(String str, String[] parsePatterns) throws ParseException { 285 return parseDateWithLeniency(str, parsePatterns, true); 286 } 287 288 //----------------------------------------------------------------------- 289 /** 290 * <p>Parses a string representing a date by trying a variety of different parsers.</p> 291 * 292 * <p>The parse will try each parse pattern in turn. 293 * A parse is only deemed successful if it parses the whole of the input string. 294 * If no parse patterns match, a ParseException is thrown.</p> 295 * The parser parses strictly - it does not allow for dates such as "February 942, 1996". 296 * 297 * @param str the date to parse, not null 298 * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null 299 * @return the parsed date 300 * @throws IllegalArgumentException if the date string or pattern array is null 301 * @throws ParseException if none of the date patterns were suitable 302 * @since 2.5 303 */ 304 public static Date parseDateStrictly(String str, String[] parsePatterns) throws ParseException { 305 return parseDateWithLeniency(str, parsePatterns, false); 306 } 307 308 /** 309 * <p>Parses a string representing a date by trying a variety of different parsers.</p> 310 * 311 * <p>The parse will try each parse pattern in turn. 312 * A parse is only deemed successful if it parses the whole of the input string. 313 * If no parse patterns match, a ParseException is thrown.</p> 314 * 315 * @param str the date to parse, not null 316 * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null 317 * @param lenient Specify whether or not date/time parsing is to be lenient. 318 * @return the parsed date 319 * @throws IllegalArgumentException if the date string or pattern array is null 320 * @throws ParseException if none of the date patterns were suitable 321 * @see java.util.Calender#isLenient() 322 */ 323 private static Date parseDateWithLeniency(String str, String[] parsePatterns, 324 boolean lenient) throws ParseException { 325 if (str == null || parsePatterns == null) { 326 throw new IllegalArgumentException("Date and Patterns must not be null"); 327 } 328 329 SimpleDateFormat parser = new SimpleDateFormat(); 330 parser.setLenient(lenient); 331 ParsePosition pos = new ParsePosition(0); 332 for (int i = 0; i < parsePatterns.length; i++) { 333 334 String pattern = parsePatterns[i]; 335 336 // LANG-530 - need to make sure 'ZZ' output doesn't get passed to SimpleDateFormat 337 if (parsePatterns[i].endsWith("ZZ")) { 338 pattern = pattern.substring(0, pattern.length() - 1); 339 } 340 341 parser.applyPattern(pattern); 342 pos.setIndex(0); 343 344 String str2 = str; 345 // LANG-530 - need to make sure 'ZZ' output doesn't hit SimpleDateFormat as it will ParseException 346 if (parsePatterns[i].endsWith("ZZ")) { 347 int signIdx = indexOfSignChars(str2, 0); 348 while (signIdx >=0) { 349 str2 = reformatTimezone(str2, signIdx); 350 signIdx = indexOfSignChars(str2, ++signIdx); 351 } 352 } 353 354 Date date = parser.parse(str2, pos); 355 if (date != null && pos.getIndex() == str2.length()) { 356 return date; 357 } 358 } 359 throw new ParseException("Unable to parse the date: " + str, -1); 360 } 361 362 /** 363 * Index of sign charaters (i.e. '+' or '-'). 364 * 365 * @param str The string to search 366 * @param startPos The start position 367 * @return the index of the first sign character or -1 if not found 368 */ 369 private static int indexOfSignChars(String str, int startPos) { 370 int idx = StringUtils.indexOf(str, '+', startPos); 371 if (idx < 0) { 372 idx = StringUtils.indexOf(str, '-', startPos); 373 } 374 return idx; 375 } 376 377 /** 378 * Reformat the timezone in a date string. 379 * 380 * @param str The input string 381 * @param signIdx The index position of the sign characters 382 * @return The reformatted string 383 */ 384 private static String reformatTimezone(String str, int signIdx) { 385 String str2 = str; 386 if (signIdx >= 0 && 387 signIdx + 5 < str.length() && 388 Character.isDigit(str.charAt(signIdx + 1)) && 389 Character.isDigit(str.charAt(signIdx + 2)) && 390 str.charAt(signIdx + 3) == ':' && 391 Character.isDigit(str.charAt(signIdx + 4)) && 392 Character.isDigit(str.charAt(signIdx + 5))) { 393 str2 = str.substring(0, signIdx + 3) + str.substring(signIdx + 4); 394 } 395 return str2; 396 } 397 398 //----------------------------------------------------------------------- 399 /** 400 * Adds a number of years to a date returning a new object. 401 * The original date object is unchanged. 402 * 403 * @param date the date, not null 404 * @param amount the amount to add, may be negative 405 * @return the new date object with the amount added 406 * @throws IllegalArgumentException if the date is null 407 */ 408 public static Date addYears(Date date, int amount) { 409 return add(date, Calendar.YEAR, amount); 410 } 411 412 //----------------------------------------------------------------------- 413 /** 414 * Adds a number of months to a date returning a new object. 415 * The original date object is unchanged. 416 * 417 * @param date the date, not null 418 * @param amount the amount to add, may be negative 419 * @return the new date object with the amount added 420 * @throws IllegalArgumentException if the date is null 421 */ 422 public static Date addMonths(Date date, int amount) { 423 return add(date, Calendar.MONTH, amount); 424 } 425 426 //----------------------------------------------------------------------- 427 /** 428 * Adds a number of weeks to a date returning a new object. 429 * The original date object is unchanged. 430 * 431 * @param date the date, not null 432 * @param amount the amount to add, may be negative 433 * @return the new date object with the amount added 434 * @throws IllegalArgumentException if the date is null 435 */ 436 public static Date addWeeks(Date date, int amount) { 437 return add(date, Calendar.WEEK_OF_YEAR, amount); 438 } 439 440 //----------------------------------------------------------------------- 441 /** 442 * Adds a number of days to a date returning a new object. 443 * The original date object is unchanged. 444 * 445 * @param date the date, not null 446 * @param amount the amount to add, may be negative 447 * @return the new date object with the amount added 448 * @throws IllegalArgumentException if the date is null 449 */ 450 public static Date addDays(Date date, int amount) { 451 return add(date, Calendar.DAY_OF_MONTH, amount); 452 } 453 454 //----------------------------------------------------------------------- 455 /** 456 * Adds a number of hours to a date returning a new object. 457 * The original date object is unchanged. 458 * 459 * @param date the date, not null 460 * @param amount the amount to add, may be negative 461 * @return the new date object with the amount added 462 * @throws IllegalArgumentException if the date is null 463 */ 464 public static Date addHours(Date date, int amount) { 465 return add(date, Calendar.HOUR_OF_DAY, amount); 466 } 467 468 //----------------------------------------------------------------------- 469 /** 470 * Adds a number of minutes to a date returning a new object. 471 * The original date object is unchanged. 472 * 473 * @param date the date, not null 474 * @param amount the amount to add, may be negative 475 * @return the new date object with the amount added 476 * @throws IllegalArgumentException if the date is null 477 */ 478 public static Date addMinutes(Date date, int amount) { 479 return add(date, Calendar.MINUTE, amount); 480 } 481 482 //----------------------------------------------------------------------- 483 /** 484 * Adds a number of seconds to a date returning a new object. 485 * The original date object is unchanged. 486 * 487 * @param date the date, not null 488 * @param amount the amount to add, may be negative 489 * @return the new date object with the amount added 490 * @throws IllegalArgumentException if the date is null 491 */ 492 public static Date addSeconds(Date date, int amount) { 493 return add(date, Calendar.SECOND, amount); 494 } 495 496 //----------------------------------------------------------------------- 497 /** 498 * Adds a number of milliseconds to a date returning a new object. 499 * The original date object is unchanged. 500 * 501 * @param date the date, not null 502 * @param amount the amount to add, may be negative 503 * @return the new date object with the amount added 504 * @throws IllegalArgumentException if the date is null 505 */ 506 public static Date addMilliseconds(Date date, int amount) { 507 return add(date, Calendar.MILLISECOND, amount); 508 } 509 510 //----------------------------------------------------------------------- 511 /** 512 * Adds to a date returning a new object. 513 * The original date object is unchanged. 514 * 515 * @param date the date, not null 516 * @param calendarField the calendar field to add to 517 * @param amount the amount to add, may be negative 518 * @return the new date object with the amount added 519 * @throws IllegalArgumentException if the date is null 520 * @deprecated Will become privately scoped in 3.0 521 */ 522 public static Date add(Date date, int calendarField, int amount) { 523 if (date == null) { 524 throw new IllegalArgumentException("The date must not be null"); 525 } 526 Calendar c = Calendar.getInstance(); 527 c.setTime(date); 528 c.add(calendarField, amount); 529 return c.getTime(); 530 } 531 532 //----------------------------------------------------------------------- 533 /** 534 * Sets the years field to a date returning a new object. 535 * The original date object is unchanged. 536 * 537 * @param date the date, not null 538 * @param amount the amount to set 539 * @return a new Date object set with the specified value 540 * @throws IllegalArgumentException if the date is null 541 * @since 2.4 542 */ 543 public static Date setYears(Date date, int amount) { 544 return set(date, Calendar.YEAR, amount); 545 } 546 547 //----------------------------------------------------------------------- 548 /** 549 * Sets the months field to a date returning a new object. 550 * The original date object is unchanged. 551 * 552 * @param date the date, not null 553 * @param amount the amount to set 554 * @return a new Date object set with the specified value 555 * @throws IllegalArgumentException if the date is null 556 * @since 2.4 557 */ 558 public static Date setMonths(Date date, int amount) { 559 return set(date, Calendar.MONTH, amount); 560 } 561 562 //----------------------------------------------------------------------- 563 /** 564 * Sets the day of month field to a date returning a new object. 565 * The original date object is unchanged. 566 * 567 * @param date the date, not null 568 * @param amount the amount to set 569 * @return a new Date object set with the specified value 570 * @throws IllegalArgumentException if the date is null 571 * @since 2.4 572 */ 573 public static Date setDays(Date date, int amount) { 574 return set(date, Calendar.DAY_OF_MONTH, amount); 575 } 576 577 //----------------------------------------------------------------------- 578 /** 579 * Sets the hours field to a date returning a new object. Hours range 580 * from 0-23. 581 * The original date object is unchanged. 582 * 583 * @param date the date, not null 584 * @param amount the amount to set 585 * @return a new Date object set with the specified value 586 * @throws IllegalArgumentException if the date is null 587 * @since 2.4 588 */ 589 public static Date setHours(Date date, int amount) { 590 return set(date, Calendar.HOUR_OF_DAY, amount); 591 } 592 593 //----------------------------------------------------------------------- 594 /** 595 * Sets the minute field to a date returning a new object. 596 * The original date object is unchanged. 597 * 598 * @param date the date, not null 599 * @param amount the amount to set 600 * @return a new Date object set with the specified value 601 * @throws IllegalArgumentException if the date is null 602 * @since 2.4 603 */ 604 public static Date setMinutes(Date date, int amount) { 605 return set(date, Calendar.MINUTE, amount); 606 } 607 608 //----------------------------------------------------------------------- 609 /** 610 * Sets the seconds field to a date returning a new object. 611 * The original date object is unchanged. 612 * 613 * @param date the date, not null 614 * @param amount the amount to set 615 * @return a new Date object set with the specified value 616 * @throws IllegalArgumentException if the date is null 617 * @since 2.4 618 */ 619 public static Date setSeconds(Date date, int amount) { 620 return set(date, Calendar.SECOND, amount); 621 } 622 623 //----------------------------------------------------------------------- 624 /** 625 * Sets the miliseconds field to a date returning a new object. 626 * The original date object is unchanged. 627 * 628 * @param date the date, not null 629 * @param amount the amount to set 630 * @return a new Date object set with the specified value 631 * @throws IllegalArgumentException if the date is null 632 * @since 2.4 633 */ 634 public static Date setMilliseconds(Date date, int amount) { 635 return set(date, Calendar.MILLISECOND, amount); 636 } 637 638 //----------------------------------------------------------------------- 639 /** 640 * Sets the specified field to a date returning a new object. 641 * This does not use a lenient calendar. 642 * The original date object is unchanged. 643 * 644 * @param date the date, not null 645 * @param calendarField the calendar field to set the amount to 646 * @param amount the amount to set 647 * @return a new Date object set with the specified value 648 * @throws IllegalArgumentException if the date is null 649 * @since 2.4 650 */ 651 private static Date set(Date date, int calendarField, int amount) { 652 if (date == null) { 653 throw new IllegalArgumentException("The date must not be null"); 654 } 655 // getInstance() returns a new object, so this method is thread safe. 656 Calendar c = Calendar.getInstance(); 657 c.setLenient(false); 658 c.setTime(date); 659 c.set(calendarField, amount); 660 return c.getTime(); 661 } 662 663 //----------------------------------------------------------------------- 664 /** 665 * <p>Round this date, leaving the field specified as the most 666 * significant field.</p> 667 * 668 * <p>For example, if you had the datetime of 28 Mar 2002 669 * 13:45:01.231, if this was passed with HOUR, it would return 670 * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it 671 * would return 1 April 2002 0:00:00.000.</p> 672 * 673 * <p>For a date in a timezone that handles the change to daylight 674 * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows. 675 * Suppose daylight saving time begins at 02:00 on March 30. Rounding a 676 * date that crosses this time would produce the following values: 677 * <ul> 678 * <li>March 30, 2003 01:10 rounds to March 30, 2003 01:00</li> 679 * <li>March 30, 2003 01:40 rounds to March 30, 2003 03:00</li> 680 * <li>March 30, 2003 02:10 rounds to March 30, 2003 03:00</li> 681 * <li>March 30, 2003 02:40 rounds to March 30, 2003 04:00</li> 682 * </ul> 683 * </p> 684 * 685 * @param date the date to work with 686 * @param field the field from <code>Calendar</code> 687 * or <code>SEMI_MONTH</code> 688 * @return the rounded date 689 * @throws IllegalArgumentException if the date is <code>null</code> 690 * @throws ArithmeticException if the year is over 280 million 691 */ 692 public static Date round(Date date, int field) { 693 if (date == null) { 694 throw new IllegalArgumentException("The date must not be null"); 695 } 696 Calendar gval = Calendar.getInstance(); 697 gval.setTime(date); 698 modify(gval, field, MODIFY_ROUND); 699 return gval.getTime(); 700 } 701 702 /** 703 * <p>Round this date, leaving the field specified as the most 704 * significant field.</p> 705 * 706 * <p>For example, if you had the datetime of 28 Mar 2002 707 * 13:45:01.231, if this was passed with HOUR, it would return 708 * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it 709 * would return 1 April 2002 0:00:00.000.</p> 710 * 711 * <p>For a date in a timezone that handles the change to daylight 712 * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows. 713 * Suppose daylight saving time begins at 02:00 on March 30. Rounding a 714 * date that crosses this time would produce the following values: 715 * <ul> 716 * <li>March 30, 2003 01:10 rounds to March 30, 2003 01:00</li> 717 * <li>March 30, 2003 01:40 rounds to March 30, 2003 03:00</li> 718 * <li>March 30, 2003 02:10 rounds to March 30, 2003 03:00</li> 719 * <li>March 30, 2003 02:40 rounds to March 30, 2003 04:00</li> 720 * </ul> 721 * </p> 722 * 723 * @param date the date to work with 724 * @param field the field from <code>Calendar</code> 725 * or <code>SEMI_MONTH</code> 726 * @return the rounded date (a different object) 727 * @throws IllegalArgumentException if the date is <code>null</code> 728 * @throws ArithmeticException if the year is over 280 million 729 */ 730 public static Calendar round(Calendar date, int field) { 731 if (date == null) { 732 throw new IllegalArgumentException("The date must not be null"); 733 } 734 Calendar rounded = (Calendar) date.clone(); 735 modify(rounded, field, MODIFY_ROUND); 736 return rounded; 737 } 738 739 /** 740 * <p>Round this date, leaving the field specified as the most 741 * significant field.</p> 742 * 743 * <p>For example, if you had the datetime of 28 Mar 2002 744 * 13:45:01.231, if this was passed with HOUR, it would return 745 * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it 746 * would return 1 April 2002 0:00:00.000.</p> 747 * 748 * <p>For a date in a timezone that handles the change to daylight 749 * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows. 750 * Suppose daylight saving time begins at 02:00 on March 30. Rounding a 751 * date that crosses this time would produce the following values: 752 * <ul> 753 * <li>March 30, 2003 01:10 rounds to March 30, 2003 01:00</li> 754 * <li>March 30, 2003 01:40 rounds to March 30, 2003 03:00</li> 755 * <li>March 30, 2003 02:10 rounds to March 30, 2003 03:00</li> 756 * <li>March 30, 2003 02:40 rounds to March 30, 2003 04:00</li> 757 * </ul> 758 * </p> 759 * 760 * @param date the date to work with, either Date or Calendar 761 * @param field the field from <code>Calendar</code> 762 * or <code>SEMI_MONTH</code> 763 * @return the rounded date 764 * @throws IllegalArgumentException if the date is <code>null</code> 765 * @throws ClassCastException if the object type is not a <code>Date</code> 766 * or <code>Calendar</code> 767 * @throws ArithmeticException if the year is over 280 million 768 */ 769 public static Date round(Object date, int field) { 770 if (date == null) { 771 throw new IllegalArgumentException("The date must not be null"); 772 } 773 if (date instanceof Date) { 774 return round((Date) date, field); 775 } else if (date instanceof Calendar) { 776 return round((Calendar) date, field).getTime(); 777 } else { 778 throw new ClassCastException("Could not round " + date); 779 } 780 } 781 782 //----------------------------------------------------------------------- 783 /** 784 * <p>Truncate this date, leaving the field specified as the most 785 * significant field.</p> 786 * 787 * <p>For example, if you had the datetime of 28 Mar 2002 788 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar 789 * 2002 13:00:00.000. If this was passed with MONTH, it would 790 * return 1 Mar 2002 0:00:00.000.</p> 791 * 792 * @param date the date to work with 793 * @param field the field from <code>Calendar</code> 794 * or <code>SEMI_MONTH</code> 795 * @return the rounded date 796 * @throws IllegalArgumentException if the date is <code>null</code> 797 * @throws ArithmeticException if the year is over 280 million 798 */ 799 public static Date truncate(Date date, int field) { 800 if (date == null) { 801 throw new IllegalArgumentException("The date must not be null"); 802 } 803 Calendar gval = Calendar.getInstance(); 804 gval.setTime(date); 805 modify(gval, field, MODIFY_TRUNCATE); 806 return gval.getTime(); 807 } 808 809 /** 810 * <p>Truncate this date, leaving the field specified as the most 811 * significant field.</p> 812 * 813 * <p>For example, if you had the datetime of 28 Mar 2002 814 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar 815 * 2002 13:00:00.000. If this was passed with MONTH, it would 816 * return 1 Mar 2002 0:00:00.000.</p> 817 * 818 * @param date the date to work with 819 * @param field the field from <code>Calendar</code> 820 * or <code>SEMI_MONTH</code> 821 * @return the rounded date (a different object) 822 * @throws IllegalArgumentException if the date is <code>null</code> 823 * @throws ArithmeticException if the year is over 280 million 824 */ 825 public static Calendar truncate(Calendar date, int field) { 826 if (date == null) { 827 throw new IllegalArgumentException("The date must not be null"); 828 } 829 Calendar truncated = (Calendar) date.clone(); 830 modify(truncated, field, MODIFY_TRUNCATE); 831 return truncated; 832 } 833 834 /** 835 * <p>Truncate this date, leaving the field specified as the most 836 * significant field.</p> 837 * 838 * <p>For example, if you had the datetime of 28 Mar 2002 839 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar 840 * 2002 13:00:00.000. If this was passed with MONTH, it would 841 * return 1 Mar 2002 0:00:00.000.</p> 842 * 843 * @param date the date to work with, either <code>Date</code> 844 * or <code>Calendar</code> 845 * @param field the field from <code>Calendar</code> 846 * or <code>SEMI_MONTH</code> 847 * @return the rounded date 848 * @throws IllegalArgumentException if the date 849 * is <code>null</code> 850 * @throws ClassCastException if the object type is not a 851 * <code>Date</code> or <code>Calendar</code> 852 * @throws ArithmeticException if the year is over 280 million 853 */ 854 public static Date truncate(Object date, int field) { 855 if (date == null) { 856 throw new IllegalArgumentException("The date must not be null"); 857 } 858 if (date instanceof Date) { 859 return truncate((Date) date, field); 860 } else if (date instanceof Calendar) { 861 return truncate((Calendar) date, field).getTime(); 862 } else { 863 throw new ClassCastException("Could not truncate " + date); 864 } 865 } 866 867 //----------------------------------------------------------------------- 868 /** 869 * <p>Ceil this date, leaving the field specified as the most 870 * significant field.</p> 871 * 872 * <p>For example, if you had the datetime of 28 Mar 2002 873 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar 874 * 2002 13:00:00.000. If this was passed with MONTH, it would 875 * return 1 Mar 2002 0:00:00.000.</p> 876 * 877 * @param date the date to work with 878 * @param field the field from <code>Calendar</code> 879 * or <code>SEMI_MONTH</code> 880 * @return the rounded date 881 * @throws IllegalArgumentException if the date is <code>null</code> 882 * @throws ArithmeticException if the year is over 280 million 883 * @since 2.5 884 */ 885 public static Date ceiling(Date date, int field) { 886 if (date == null) { 887 throw new IllegalArgumentException("The date must not be null"); 888 } 889 Calendar gval = Calendar.getInstance(); 890 gval.setTime(date); 891 modify(gval, field, MODIFY_CEILING); 892 return gval.getTime(); 893 } 894 895 /** 896 * <p>Ceil this date, leaving the field specified as the most 897 * significant field.</p> 898 * 899 * <p>For example, if you had the datetime of 28 Mar 2002 900 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar 901 * 2002 13:00:00.000. If this was passed with MONTH, it would 902 * return 1 Mar 2002 0:00:00.000.</p> 903 * 904 * @param date the date to work with 905 * @param field the field from <code>Calendar</code> 906 * or <code>SEMI_MONTH</code> 907 * @return the rounded date (a different object) 908 * @throws IllegalArgumentException if the date is <code>null</code> 909 * @throws ArithmeticException if the year is over 280 million 910 * @since 2.5 911 */ 912 public static Calendar ceiling(Calendar date, int field) { 913 if (date == null) { 914 throw new IllegalArgumentException("The date must not be null"); 915 } 916 Calendar ceiled = (Calendar) date.clone(); 917 modify(ceiled, field, MODIFY_CEILING); 918 return ceiled; 919 } 920 921 /** 922 * <p>Ceil this date, leaving the field specified as the most 923 * significant field.</p> 924 * 925 * <p>For example, if you had the datetime of 28 Mar 2002 926 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar 927 * 2002 13:00:00.000. If this was passed with MONTH, it would 928 * return 1 Mar 2002 0:00:00.000.</p> 929 * 930 * @param date the date to work with, either <code>Date</code> 931 * or <code>Calendar</code> 932 * @param field the field from <code>Calendar</code> 933 * or <code>SEMI_MONTH</code> 934 * @return the rounded date 935 * @throws IllegalArgumentException if the date 936 * is <code>null</code> 937 * @throws ClassCastException if the object type is not a 938 * <code>Date</code> or <code>Calendar</code> 939 * @throws ArithmeticException if the year is over 280 million 940 * @since 2.5 941 */ 942 public static Date ceiling(Object date, int field) { 943 if (date == null) { 944 throw new IllegalArgumentException("The date must not be null"); 945 } 946 if (date instanceof Date) { 947 return ceiling((Date) date, field); 948 } else if (date instanceof Calendar) { 949 return ceiling((Calendar) date, field).getTime(); 950 } else { 951 throw new ClassCastException("Could not find ceiling of for type: " + date.getClass()); 952 } 953 } 954 955 //----------------------------------------------------------------------- 956 /** 957 * <p>Internal calculation method.</p> 958 * 959 * @param val the calendar 960 * @param field the field constant 961 * @param modType type to truncate, round or ceiling 962 * @throws ArithmeticException if the year is over 280 million 963 */ 964 private static void modify(Calendar val, int field, int modType) { 965 if (val.get(Calendar.YEAR) > 280000000) { 966 throw new ArithmeticException("Calendar value too large for accurate calculations"); 967 } 968 969 if (field == Calendar.MILLISECOND) { 970 return; 971 } 972 973 // ----------------- Fix for LANG-59 ---------------------- START --------------- 974 // see http://issues.apache.org/jira/browse/LANG-59 975 // 976 // Manually truncate milliseconds, seconds and minutes, rather than using 977 // Calendar methods. 978 979 Date date = val.getTime(); 980 long time = date.getTime(); 981 boolean done = false; 982 983 // truncate milliseconds 984 int millisecs = val.get(Calendar.MILLISECOND); 985 if (MODIFY_TRUNCATE == modType || millisecs < 500) { 986 time = time - millisecs; 987 } 988 if (field == Calendar.SECOND) { 989 done = true; 990 } 991 992 // truncate seconds 993 int seconds = val.get(Calendar.SECOND); 994 if (!done && (MODIFY_TRUNCATE == modType || seconds < 30)) { 995 time = time - (seconds * 1000L); 996 } 997 if (field == Calendar.MINUTE) { 998 done = true; 999 } 1000 1001 // truncate minutes 1002 int minutes = val.get(Calendar.MINUTE); 1003 if (!done && (MODIFY_TRUNCATE == modType || minutes < 30)) { 1004 time = time - (minutes * 60000L); 1005 } 1006 1007 // reset time 1008 if (date.getTime() != time) { 1009 date.setTime(time); 1010 val.setTime(date); 1011 } 1012 // ----------------- Fix for LANG-59 ----------------------- END ---------------- 1013 1014 boolean roundUp = false; 1015 for (int i = 0; i < fields.length; i++) { 1016 for (int j = 0; j < fields[i].length; j++) { 1017 if (fields[i][j] == field) { 1018 //This is our field... we stop looping 1019 if (modType == MODIFY_CEILING || (modType == MODIFY_ROUND && roundUp)) { 1020 if (field == DateUtils.SEMI_MONTH) { 1021 //This is a special case that's hard to generalize 1022 //If the date is 1, we round up to 16, otherwise 1023 // we subtract 15 days and add 1 month 1024 if (val.get(Calendar.DATE) == 1) { 1025 val.add(Calendar.DATE, 15); 1026 } else { 1027 val.add(Calendar.DATE, -15); 1028 val.add(Calendar.MONTH, 1); 1029 } 1030 // ----------------- Fix for LANG-440 ---------------------- START --------------- 1031 } else if (field == Calendar.AM_PM) { 1032 // This is a special case 1033 // If the time is 0, we round up to 12, otherwise 1034 // we subtract 12 hours and add 1 day 1035 if (val.get(Calendar.HOUR_OF_DAY) == 0) { 1036 val.add(Calendar.HOUR_OF_DAY, 12); 1037 } else { 1038 val.add(Calendar.HOUR_OF_DAY, -12); 1039 val.add(Calendar.DATE, 1); 1040 } 1041 // ----------------- Fix for LANG-440 ---------------------- END --------------- 1042 } else { 1043 //We need at add one to this field since the 1044 // last number causes us to round up 1045 val.add(fields[i][0], 1); 1046 } 1047 } 1048 return; 1049 } 1050 } 1051 //We have various fields that are not easy roundings 1052 int offset = 0; 1053 boolean offsetSet = false; 1054 //These are special types of fields that require different rounding rules 1055 switch (field) { 1056 case DateUtils.SEMI_MONTH: 1057 if (fields[i][0] == Calendar.DATE) { 1058 //If we're going to drop the DATE field's value, 1059 // we want to do this our own way. 1060 //We need to subtrace 1 since the date has a minimum of 1 1061 offset = val.get(Calendar.DATE) - 1; 1062 //If we're above 15 days adjustment, that means we're in the 1063 // bottom half of the month and should stay accordingly. 1064 if (offset >= 15) { 1065 offset -= 15; 1066 } 1067 //Record whether we're in the top or bottom half of that range 1068 roundUp = offset > 7; 1069 offsetSet = true; 1070 } 1071 break; 1072 case Calendar.AM_PM: 1073 if (fields[i][0] == Calendar.HOUR_OF_DAY) { 1074 //If we're going to drop the HOUR field's value, 1075 // we want to do this our own way. 1076 offset = val.get(Calendar.HOUR_OF_DAY); 1077 if (offset >= 12) { 1078 offset -= 12; 1079 } 1080 roundUp = offset >= 6; 1081 offsetSet = true; 1082 } 1083 break; 1084 } 1085 if (!offsetSet) { 1086 int min = val.getActualMinimum(fields[i][0]); 1087 int max = val.getActualMaximum(fields[i][0]); 1088 //Calculate the offset from the minimum allowed value 1089 offset = val.get(fields[i][0]) - min; 1090 //Set roundUp if this is more than half way between the minimum and maximum 1091 roundUp = offset > ((max - min) / 2); 1092 } 1093 //We need to remove this field 1094 if (offset != 0) { 1095 val.set(fields[i][0], val.get(fields[i][0]) - offset); 1096 } 1097 } 1098 throw new IllegalArgumentException("The field " + field + " is not supported"); 1099 1100 } 1101 1102 //----------------------------------------------------------------------- 1103 /** 1104 * <p>This constructs an <code>Iterator</code> over each day in a date 1105 * range defined by a focus date and range style.</p> 1106 * 1107 * <p>For instance, passing Thursday, July 4, 2002 and a 1108 * <code>RANGE_MONTH_SUNDAY</code> will return an <code>Iterator</code> 1109 * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3, 1110 * 2002, returning a Calendar instance for each intermediate day.</p> 1111 * 1112 * <p>This method provides an iterator that returns Calendar objects. 1113 * The days are progressed using {@link Calendar#add(int, int)}.</p> 1114 * 1115 * @param focus the date to work with, not null 1116 * @param rangeStyle the style constant to use. Must be one of 1117 * {@link DateUtils#RANGE_MONTH_SUNDAY}, 1118 * {@link DateUtils#RANGE_MONTH_MONDAY}, 1119 * {@link DateUtils#RANGE_WEEK_SUNDAY}, 1120 * {@link DateUtils#RANGE_WEEK_MONDAY}, 1121 * {@link DateUtils#RANGE_WEEK_RELATIVE}, 1122 * {@link DateUtils#RANGE_WEEK_CENTER} 1123 * @return the date iterator, which always returns Calendar instances 1124 * @throws IllegalArgumentException if the date is <code>null</code> 1125 * @throws IllegalArgumentException if the rangeStyle is invalid 1126 */ 1127 public static Iterator iterator(Date focus, int rangeStyle) { 1128 if (focus == null) { 1129 throw new IllegalArgumentException("The date must not be null"); 1130 } 1131 Calendar gval = Calendar.getInstance(); 1132 gval.setTime(focus); 1133 return iterator(gval, rangeStyle); 1134 } 1135 1136 /** 1137 * <p>This constructs an <code>Iterator</code> over each day in a date 1138 * range defined by a focus date and range style.</p> 1139 * 1140 * <p>For instance, passing Thursday, July 4, 2002 and a 1141 * <code>RANGE_MONTH_SUNDAY</code> will return an <code>Iterator</code> 1142 * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3, 1143 * 2002, returning a Calendar instance for each intermediate day.</p> 1144 * 1145 * <p>This method provides an iterator that returns Calendar objects. 1146 * The days are progressed using {@link Calendar#add(int, int)}.</p> 1147 * 1148 * @param focus the date to work with 1149 * @param rangeStyle the style constant to use. Must be one of 1150 * {@link DateUtils#RANGE_MONTH_SUNDAY}, 1151 * {@link DateUtils#RANGE_MONTH_MONDAY}, 1152 * {@link DateUtils#RANGE_WEEK_SUNDAY}, 1153 * {@link DateUtils#RANGE_WEEK_MONDAY}, 1154 * {@link DateUtils#RANGE_WEEK_RELATIVE}, 1155 * {@link DateUtils#RANGE_WEEK_CENTER} 1156 * @return the date iterator 1157 * @throws IllegalArgumentException if the date is <code>null</code> 1158 * @throws IllegalArgumentException if the rangeStyle is invalid 1159 */ 1160 public static Iterator iterator(Calendar focus, int rangeStyle) { 1161 if (focus == null) { 1162 throw new IllegalArgumentException("The date must not be null"); 1163 } 1164 Calendar start = null; 1165 Calendar end = null; 1166 int startCutoff = Calendar.SUNDAY; 1167 int endCutoff = Calendar.SATURDAY; 1168 switch (rangeStyle) { 1169 case RANGE_MONTH_SUNDAY: 1170 case RANGE_MONTH_MONDAY: 1171 //Set start to the first of the month 1172 start = truncate(focus, Calendar.MONTH); 1173 //Set end to the last of the month 1174 end = (Calendar) start.clone(); 1175 end.add(Calendar.MONTH, 1); 1176 end.add(Calendar.DATE, -1); 1177 //Loop start back to the previous sunday or monday 1178 if (rangeStyle == RANGE_MONTH_MONDAY) { 1179 startCutoff = Calendar.MONDAY; 1180 endCutoff = Calendar.SUNDAY; 1181 } 1182 break; 1183 case RANGE_WEEK_SUNDAY: 1184 case RANGE_WEEK_MONDAY: 1185 case RANGE_WEEK_RELATIVE: 1186 case RANGE_WEEK_CENTER: 1187 //Set start and end to the current date 1188 start = truncate(focus, Calendar.DATE); 1189 end = truncate(focus, Calendar.DATE); 1190 switch (rangeStyle) { 1191 case RANGE_WEEK_SUNDAY: 1192 //already set by default 1193 break; 1194 case RANGE_WEEK_MONDAY: 1195 startCutoff = Calendar.MONDAY; 1196 endCutoff = Calendar.SUNDAY; 1197 break; 1198 case RANGE_WEEK_RELATIVE: 1199 startCutoff = focus.get(Calendar.DAY_OF_WEEK); 1200 endCutoff = startCutoff - 1; 1201 break; 1202 case RANGE_WEEK_CENTER: 1203 startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3; 1204 endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3; 1205 break; 1206 } 1207 break; 1208 default: 1209 throw new IllegalArgumentException("The range style " + rangeStyle + " is not valid."); 1210 } 1211 if (startCutoff < Calendar.SUNDAY) { 1212 startCutoff += 7; 1213 } 1214 if (startCutoff > Calendar.SATURDAY) { 1215 startCutoff -= 7; 1216 } 1217 if (endCutoff < Calendar.SUNDAY) { 1218 endCutoff += 7; 1219 } 1220 if (endCutoff > Calendar.SATURDAY) { 1221 endCutoff -= 7; 1222 } 1223 while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) { 1224 start.add(Calendar.DATE, -1); 1225 } 1226 while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) { 1227 end.add(Calendar.DATE, 1); 1228 } 1229 return new DateIterator(start, end); 1230 } 1231 1232 /** 1233 * <p>This constructs an <code>Iterator</code> over each day in a date 1234 * range defined by a focus date and range style.</p> 1235 * 1236 * <p>For instance, passing Thursday, July 4, 2002 and a 1237 * <code>RANGE_MONTH_SUNDAY</code> will return an <code>Iterator</code> 1238 * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3, 1239 * 2002, returning a Calendar instance for each intermediate day.</p> 1240 * 1241 * @param focus the date to work with, either 1242 * <code>Date</code> or <code>Calendar</code> 1243 * @param rangeStyle the style constant to use. Must be one of the range 1244 * styles listed for the {@link #iterator(Calendar, int)} method. 1245 * @return the date iterator 1246 * @throws IllegalArgumentException if the date 1247 * is <code>null</code> 1248 * @throws ClassCastException if the object type is 1249 * not a <code>Date</code> or <code>Calendar</code> 1250 */ 1251 public static Iterator iterator(Object focus, int rangeStyle) { 1252 if (focus == null) { 1253 throw new IllegalArgumentException("The date must not be null"); 1254 } 1255 if (focus instanceof Date) { 1256 return iterator((Date) focus, rangeStyle); 1257 } else if (focus instanceof Calendar) { 1258 return iterator((Calendar) focus, rangeStyle); 1259 } else { 1260 throw new ClassCastException("Could not iterate based on " + focus); 1261 } 1262 } 1263 1264 /** 1265 * <p>Returns the number of milliseconds within the 1266 * fragment. All datefields greater than the fragment will be ignored.</p> 1267 * 1268 * <p>Asking the milliseconds of any date will only return the number of milliseconds 1269 * of the current second (resulting in a number between 0 and 999). This 1270 * method will retrieve the number of milliseconds for any fragment. 1271 * For example, if you want to calculate the number of milliseconds past today, 1272 * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will 1273 * be all milliseconds of the past hour(s), minutes(s) and second(s).</p> 1274 * 1275 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1276 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1277 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1278 * A fragment less than or equal to a SECOND field will return 0.</p> 1279 * 1280 * <p> 1281 * <ul> 1282 * <li>January 1, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538</li> 1283 * <li>January 6, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538</li> 1284 * <li>January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10538 (10*1000 + 538)</li> 1285 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 1286 * (a millisecond cannot be split in milliseconds)</li> 1287 * </ul> 1288 * </p> 1289 * 1290 * @param date the date to work with, not null 1291 * @param fragment the Calendar field part of date to calculate 1292 * @return number of milliseconds within the fragment of date 1293 * @throws IllegalArgumentException if the date is <code>null</code> or 1294 * fragment is not supported 1295 * @since 2.4 1296 */ 1297 public static long getFragmentInMilliseconds(Date date, int fragment) { 1298 return getFragment(date, fragment, Calendar.MILLISECOND); 1299 } 1300 1301 /** 1302 * <p>Returns the number of seconds within the 1303 * fragment. All datefields greater than the fragment will be ignored.</p> 1304 * 1305 * <p>Asking the seconds of any date will only return the number of seconds 1306 * of the current minute (resulting in a number between 0 and 59). This 1307 * method will retrieve the number of seconds for any fragment. 1308 * For example, if you want to calculate the number of seconds past today, 1309 * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will 1310 * be all seconds of the past hour(s) and minutes(s).</p> 1311 * 1312 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1313 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1314 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1315 * A fragment less than or equal to a SECOND field will return 0.</p> 1316 * 1317 * <p> 1318 * <ul> 1319 * <li>January 1, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10 1320 * (equivalent to deprecated date.getSeconds())</li> 1321 * <li>January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10 1322 * (equivalent to deprecated date.getSeconds())</li> 1323 * <li>January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 26110 1324 * (7*3600 + 15*60 + 10)</li> 1325 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 1326 * (a millisecond cannot be split in seconds)</li> 1327 * </ul> 1328 * </p> 1329 * 1330 * @param date the date to work with, not null 1331 * @param fragment the Calendar field part of date to calculate 1332 * @return number of seconds within the fragment of date 1333 * @throws IllegalArgumentException if the date is <code>null</code> or 1334 * fragment is not supported 1335 * @since 2.4 1336 */ 1337 public static long getFragmentInSeconds(Date date, int fragment) { 1338 return getFragment(date, fragment, Calendar.SECOND); 1339 } 1340 1341 /** 1342 * <p>Returns the number of minutes within the 1343 * fragment. All datefields greater than the fragment will be ignored.</p> 1344 * 1345 * <p>Asking the minutes of any date will only return the number of minutes 1346 * of the current hour (resulting in a number between 0 and 59). This 1347 * method will retrieve the number of minutes for any fragment. 1348 * For example, if you want to calculate the number of minutes past this month, 1349 * your fragment is Calendar.MONTH. The result will be all minutes of the 1350 * past day(s) and hour(s).</p> 1351 * 1352 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1353 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1354 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1355 * A fragment less than or equal to a MINUTE field will return 0.</p> 1356 * 1357 * <p> 1358 * <ul> 1359 * <li>January 1, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15 1360 * (equivalent to deprecated date.getMinutes())</li> 1361 * <li>January 6, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15 1362 * (equivalent to deprecated date.getMinutes())</li> 1363 * <li>January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 15</li> 1364 * <li>January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 435 (7*60 + 15)</li> 1365 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 1366 * (a millisecond cannot be split in minutes)</li> 1367 * </ul> 1368 * </p> 1369 * 1370 * @param date the date to work with, not null 1371 * @param fragment the Calendar field part of date to calculate 1372 * @return number of minutes within the fragment of date 1373 * @throws IllegalArgumentException if the date is <code>null</code> or 1374 * fragment is not supported 1375 * @since 2.4 1376 */ 1377 public static long getFragmentInMinutes(Date date, int fragment) { 1378 return getFragment(date, fragment, Calendar.MINUTE); 1379 } 1380 1381 /** 1382 * <p>Returns the number of hours within the 1383 * fragment. All datefields greater than the fragment will be ignored.</p> 1384 * 1385 * <p>Asking the hours of any date will only return the number of hours 1386 * of the current day (resulting in a number between 0 and 23). This 1387 * method will retrieve the number of hours for any fragment. 1388 * For example, if you want to calculate the number of hours past this month, 1389 * your fragment is Calendar.MONTH. The result will be all hours of the 1390 * past day(s).</p> 1391 * 1392 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1393 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1394 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1395 * A fragment less than or equal to a HOUR field will return 0.</p> 1396 * 1397 * <p> 1398 * <ul> 1399 * <li>January 1, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7 1400 * (equivalent to deprecated date.getHours())</li> 1401 * <li>January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7 1402 * (equivalent to deprecated date.getHours())</li> 1403 * <li>January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 7</li> 1404 * <li>January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 127 (5*24 + 7)</li> 1405 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 1406 * (a millisecond cannot be split in hours)</li> 1407 * </ul> 1408 * </p> 1409 * 1410 * @param date the date to work with, not null 1411 * @param fragment the Calendar field part of date to calculate 1412 * @return number of hours within the fragment of date 1413 * @throws IllegalArgumentException if the date is <code>null</code> or 1414 * fragment is not supported 1415 * @since 2.4 1416 */ 1417 public static long getFragmentInHours(Date date, int fragment) { 1418 return getFragment(date, fragment, Calendar.HOUR_OF_DAY); 1419 } 1420 1421 /** 1422 * <p>Returns the number of days within the 1423 * fragment. All datefields greater than the fragment will be ignored.</p> 1424 * 1425 * <p>Asking the days of any date will only return the number of days 1426 * of the current month (resulting in a number between 1 and 31). This 1427 * method will retrieve the number of days for any fragment. 1428 * For example, if you want to calculate the number of days past this year, 1429 * your fragment is Calendar.YEAR. The result will be all days of the 1430 * past month(s).</p> 1431 * 1432 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1433 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1434 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1435 * A fragment less than or equal to a DAY field will return 0.</p> 1436 * 1437 * <p> 1438 * <ul> 1439 * <li>January 28, 2008 with Calendar.MONTH as fragment will return 28 1440 * (equivalent to deprecated date.getDay())</li> 1441 * <li>February 28, 2008 with Calendar.MONTH as fragment will return 28 1442 * (equivalent to deprecated date.getDay())</li> 1443 * <li>January 28, 2008 with Calendar.YEAR as fragment will return 28</li> 1444 * <li>February 28, 2008 with Calendar.YEAR as fragment will return 59</li> 1445 * <li>January 28, 2008 with Calendar.MILLISECOND as fragment will return 0 1446 * (a millisecond cannot be split in days)</li> 1447 * </ul> 1448 * </p> 1449 * 1450 * @param date the date to work with, not null 1451 * @param fragment the Calendar field part of date to calculate 1452 * @return number of days within the fragment of date 1453 * @throws IllegalArgumentException if the date is <code>null</code> or 1454 * fragment is not supported 1455 * @since 2.4 1456 */ 1457 public static long getFragmentInDays(Date date, int fragment) { 1458 return getFragment(date, fragment, Calendar.DAY_OF_YEAR); 1459 } 1460 1461 /** 1462 * <p>Returns the number of milliseconds within the 1463 * fragment. All datefields greater than the fragment will be ignored.</p> 1464 * 1465 * <p>Asking the milliseconds of any date will only return the number of milliseconds 1466 * of the current second (resulting in a number between 0 and 999). This 1467 * method will retrieve the number of milliseconds for any fragment. 1468 * For example, if you want to calculate the number of seconds past today, 1469 * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will 1470 * be all seconds of the past hour(s), minutes(s) and second(s).</p> 1471 * 1472 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1473 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1474 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1475 * A fragment less than or equal to a MILLISECOND field will return 0.</p> 1476 * 1477 * <p> 1478 * <ul> 1479 * <li>January 1, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538 1480 * (equivalent to calendar.get(Calendar.MILLISECOND))</li> 1481 * <li>January 6, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538 1482 * (equivalent to calendar.get(Calendar.MILLISECOND))</li> 1483 * <li>January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10538 1484 * (10*1000 + 538)</li> 1485 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 1486 * (a millisecond cannot be split in milliseconds)</li> 1487 * </ul> 1488 * </p> 1489 * 1490 * @param calendar the calendar to work with, not null 1491 * @param fragment the Calendar field part of calendar to calculate 1492 * @return number of milliseconds within the fragment of date 1493 * @throws IllegalArgumentException if the date is <code>null</code> or 1494 * fragment is not supported 1495 * @since 2.4 1496 */ 1497 public static long getFragmentInMilliseconds(Calendar calendar, int fragment) { 1498 return getFragment(calendar, fragment, Calendar.MILLISECOND); 1499 } 1500 /** 1501 * <p>Returns the number of seconds within the 1502 * fragment. All datefields greater than the fragment will be ignored.</p> 1503 * 1504 * <p>Asking the seconds of any date will only return the number of seconds 1505 * of the current minute (resulting in a number between 0 and 59). This 1506 * method will retrieve the number of seconds for any fragment. 1507 * For example, if you want to calculate the number of seconds past today, 1508 * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will 1509 * be all seconds of the past hour(s) and minutes(s).</p> 1510 * 1511 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1512 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1513 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1514 * A fragment less than or equal to a SECOND field will return 0.</p> 1515 * 1516 * <p> 1517 * <ul> 1518 * <li>January 1, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10 1519 * (equivalent to calendar.get(Calendar.SECOND))</li> 1520 * <li>January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10 1521 * (equivalent to calendar.get(Calendar.SECOND))</li> 1522 * <li>January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 26110 1523 * (7*3600 + 15*60 + 10)</li> 1524 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 1525 * (a millisecond cannot be split in seconds)</li> 1526 * </ul> 1527 * </p> 1528 * 1529 * @param calendar the calendar to work with, not null 1530 * @param fragment the Calendar field part of calendar to calculate 1531 * @return number of seconds within the fragment of date 1532 * @throws IllegalArgumentException if the date is <code>null</code> or 1533 * fragment is not supported 1534 * @since 2.4 1535 */ 1536 public static long getFragmentInSeconds(Calendar calendar, int fragment) { 1537 return getFragment(calendar, fragment, Calendar.SECOND); 1538 } 1539 1540 /** 1541 * <p>Returns the number of minutes within the 1542 * fragment. All datefields greater than the fragment will be ignored.</p> 1543 * 1544 * <p>Asking the minutes of any date will only return the number of minutes 1545 * of the current hour (resulting in a number between 0 and 59). This 1546 * method will retrieve the number of minutes for any fragment. 1547 * For example, if you want to calculate the number of minutes past this month, 1548 * your fragment is Calendar.MONTH. The result will be all minutes of the 1549 * past day(s) and hour(s).</p> 1550 * 1551 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1552 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1553 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1554 * A fragment less than or equal to a MINUTE field will return 0.</p> 1555 * 1556 * <p> 1557 * <ul> 1558 * <li>January 1, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15 1559 * (equivalent to calendar.get(Calendar.MINUTES))</li> 1560 * <li>January 6, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15 1561 * (equivalent to calendar.get(Calendar.MINUTES))</li> 1562 * <li>January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 15</li> 1563 * <li>January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 435 (7*60 + 15)</li> 1564 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 1565 * (a millisecond cannot be split in minutes)</li> 1566 * </ul> 1567 * </p> 1568 * 1569 * @param calendar the calendar to work with, not null 1570 * @param fragment the Calendar field part of calendar to calculate 1571 * @return number of minutes within the fragment of date 1572 * @throws IllegalArgumentException if the date is <code>null</code> or 1573 * fragment is not supported 1574 * @since 2.4 1575 */ 1576 public static long getFragmentInMinutes(Calendar calendar, int fragment) { 1577 return getFragment(calendar, fragment, Calendar.MINUTE); 1578 } 1579 1580 /** 1581 * <p>Returns the number of hours within the 1582 * fragment. All datefields greater than the fragment will be ignored.</p> 1583 * 1584 * <p>Asking the hours of any date will only return the number of hours 1585 * of the current day (resulting in a number between 0 and 23). This 1586 * method will retrieve the number of hours for any fragment. 1587 * For example, if you want to calculate the number of hours past this month, 1588 * your fragment is Calendar.MONTH. The result will be all hours of the 1589 * past day(s).</p> 1590 * 1591 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1592 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1593 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1594 * A fragment less than or equal to a HOUR field will return 0.</p> 1595 * 1596 * <p> 1597 * <ul> 1598 * <li>January 1, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7 1599 * (equivalent to calendar.get(Calendar.HOUR_OF_DAY))</li> 1600 * <li>January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7 1601 * (equivalent to calendar.get(Calendar.HOUR_OF_DAY))</li> 1602 * <li>January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 7</li> 1603 * <li>January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 127 (5*24 + 7)</li> 1604 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 1605 * (a millisecond cannot be split in hours)</li> 1606 * </ul> 1607 * </p> 1608 * 1609 * @param calendar the calendar to work with, not null 1610 * @param fragment the Calendar field part of calendar to calculate 1611 * @return number of hours within the fragment of date 1612 * @throws IllegalArgumentException if the date is <code>null</code> or 1613 * fragment is not supported 1614 * @since 2.4 1615 */ 1616 public static long getFragmentInHours(Calendar calendar, int fragment) { 1617 return getFragment(calendar, fragment, Calendar.HOUR_OF_DAY); 1618 } 1619 1620 /** 1621 * <p>Returns the number of days within the 1622 * fragment. All datefields greater than the fragment will be ignored.</p> 1623 * 1624 * <p>Asking the days of any date will only return the number of days 1625 * of the current month (resulting in a number between 1 and 31). This 1626 * method will retrieve the number of days for any fragment. 1627 * For example, if you want to calculate the number of days past this year, 1628 * your fragment is Calendar.YEAR. The result will be all days of the 1629 * past month(s).</p> 1630 * 1631 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both 1632 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, 1633 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND 1634 * A fragment less than or equal to a DAY field will return 0.</p> 1635 * 1636 * <p> 1637 * <ul> 1638 * <li>January 28, 2008 with Calendar.MONTH as fragment will return 28 1639 * (equivalent to calendar.get(Calendar.DAY_OF_MONTH))</li> 1640 * <li>February 28, 2008 with Calendar.MONTH as fragment will return 28 1641 * (equivalent to calendar.get(Calendar.DAY_OF_MONTH))</li> 1642 * <li>January 28, 2008 with Calendar.YEAR as fragment will return 28 1643 * (equivalent to calendar.get(Calendar.DAY_OF_YEAR))</li> 1644 * <li>February 28, 2008 with Calendar.YEAR as fragment will return 59 1645 * (equivalent to calendar.get(Calendar.DAY_OF_YEAR))</li> 1646 * <li>January 28, 2008 with Calendar.MILLISECOND as fragment will return 0 1647 * (a millisecond cannot be split in days)</li> 1648 * </ul> 1649 * </p> 1650 * 1651 * @param calendar the calendar to work with, not null 1652 * @param fragment the Calendar field part of calendar to calculate 1653 * @return number of days within the fragment of date 1654 * @throws IllegalArgumentException if the date is <code>null</code> or 1655 * fragment is not supported 1656 * @since 2.4 1657 */ 1658 public static long getFragmentInDays(Calendar calendar, int fragment) { 1659 return getFragment(calendar, fragment, Calendar.DAY_OF_YEAR); 1660 } 1661 1662 /** 1663 * Date-version for fragment-calculation in any unit 1664 * 1665 * @param date the date to work with, not null 1666 * @param fragment the Calendar field part of date to calculate 1667 * @param unit Calendar field defining the unit 1668 * @return number of units within the fragment of the date 1669 * @throws IllegalArgumentException if the date is <code>null</code> or 1670 * fragment is not supported 1671 * @since 2.4 1672 */ 1673 private static long getFragment(Date date, int fragment, int unit) { 1674 if(date == null) { 1675 throw new IllegalArgumentException("The date must not be null"); 1676 } 1677 Calendar calendar = Calendar.getInstance(); 1678 calendar.setTime(date); 1679 return getFragment(calendar, fragment, unit); 1680 } 1681 1682 /** 1683 * Calendar-version for fragment-calculation in any unit 1684 * 1685 * @param calendar the calendar to work with, not null 1686 * @param fragment the Calendar field part of calendar to calculate 1687 * @param unit Calendar field defining the unit 1688 * @return number of units within the fragment of the calendar 1689 * @throws IllegalArgumentException if the date is <code>null</code> or 1690 * fragment is not supported 1691 * @since 2.4 1692 */ 1693 private static long getFragment(Calendar calendar, int fragment, int unit) { 1694 if(calendar == null) { 1695 throw new IllegalArgumentException("The date must not be null"); 1696 } 1697 long millisPerUnit = getMillisPerUnit(unit); 1698 long result = 0; 1699 1700 // Fragments bigger than a day require a breakdown to days 1701 switch (fragment) { 1702 case Calendar.YEAR: 1703 result += (calendar.get(Calendar.DAY_OF_YEAR) * MILLIS_PER_DAY) / millisPerUnit; 1704 break; 1705 case Calendar.MONTH: 1706 result += (calendar.get(Calendar.DAY_OF_MONTH) * MILLIS_PER_DAY) / millisPerUnit; 1707 break; 1708 } 1709 1710 switch (fragment) { 1711 // Number of days already calculated for these cases 1712 case Calendar.YEAR: 1713 case Calendar.MONTH: 1714 1715 // The rest of the valid cases 1716 case Calendar.DAY_OF_YEAR: 1717 case Calendar.DATE: 1718 result += (calendar.get(Calendar.HOUR_OF_DAY) * MILLIS_PER_HOUR) / millisPerUnit; 1719 //$FALL-THROUGH$ 1720 case Calendar.HOUR_OF_DAY: 1721 result += (calendar.get(Calendar.MINUTE) * MILLIS_PER_MINUTE) / millisPerUnit; 1722 //$FALL-THROUGH$ 1723 case Calendar.MINUTE: 1724 result += (calendar.get(Calendar.SECOND) * MILLIS_PER_SECOND) / millisPerUnit; 1725 //$FALL-THROUGH$ 1726 case Calendar.SECOND: 1727 result += (calendar.get(Calendar.MILLISECOND) * 1) / millisPerUnit; 1728 break; 1729 case Calendar.MILLISECOND: 1730 break;//never useful 1731 default: 1732 throw new IllegalArgumentException("The fragment " + fragment + " is not supported"); 1733 } 1734 return result; 1735 } 1736 1737 /** 1738 * Returns the number of millis of a datefield, if this is a constant value 1739 * 1740 * @param unit A Calendar field which is a valid unit for a fragment 1741 * @return number of millis 1742 * @throws IllegalArgumentException if date can't be represented in millisenconds 1743 * @since 2.4 1744 */ 1745 private static long getMillisPerUnit(int unit) { 1746 long result = Long.MAX_VALUE; 1747 switch (unit) { 1748 case Calendar.DAY_OF_YEAR: 1749 case Calendar.DATE: 1750 result = MILLIS_PER_DAY; 1751 break; 1752 case Calendar.HOUR_OF_DAY: 1753 result = MILLIS_PER_HOUR; 1754 break; 1755 case Calendar.MINUTE: 1756 result = MILLIS_PER_MINUTE; 1757 break; 1758 case Calendar.SECOND: 1759 result = MILLIS_PER_SECOND; 1760 break; 1761 case Calendar.MILLISECOND: 1762 result = 1; 1763 break; 1764 default: throw new IllegalArgumentException("The unit " + unit + " cannot be represented is milleseconds"); 1765 } 1766 return result; 1767 } 1768 1769 /** 1770 * <p>Date iterator.</p> 1771 */ 1772 static class DateIterator implements Iterator { 1773 private final Calendar endFinal; 1774 private final Calendar spot; 1775 1776 /** 1777 * Constructs a DateIterator that ranges from one date to another. 1778 * 1779 * @param startFinal start date (inclusive) 1780 * @param endFinal end date (not inclusive) 1781 */ 1782 DateIterator(Calendar startFinal, Calendar endFinal) { 1783 super(); 1784 this.endFinal = endFinal; 1785 spot = startFinal; 1786 spot.add(Calendar.DATE, -1); 1787 } 1788 1789 /** 1790 * Has the iterator not reached the end date yet? 1791 * 1792 * @return <code>true</code> if the iterator has yet to reach the end date 1793 */ 1794 public boolean hasNext() { 1795 return spot.before(endFinal); 1796 } 1797 1798 /** 1799 * Return the next calendar in the iteration 1800 * 1801 * @return Object calendar for the next date 1802 */ 1803 public Object next() { 1804 if (spot.equals(endFinal)) { 1805 throw new NoSuchElementException(); 1806 } 1807 spot.add(Calendar.DATE, 1); 1808 return spot.clone(); 1809 } 1810 1811 /** 1812 * Always throws UnsupportedOperationException. 1813 * 1814 * @throws UnsupportedOperationException 1815 * @see java.util.Iterator#remove() 1816 */ 1817 public void remove() { 1818 throw new UnsupportedOperationException(); 1819 } 1820 } 1821 1822 //------------------------------------------------------------------------- 1823 // Deprecated int constants 1824 // TODO: Remove in 3.0 1825 1826 /** 1827 * Number of milliseconds in a standard second. 1828 * 1829 * @deprecated Use MILLIS_PER_SECOND. This will be removed in Commons Lang 3.0. 1830 */ 1831 public static final int MILLIS_IN_SECOND = 1000; 1832 /** 1833 * Number of milliseconds in a standard minute. 1834 * 1835 * @deprecated Use MILLIS_PER_MINUTE. This will be removed in Commons Lang 3.0. 1836 */ 1837 public static final int MILLIS_IN_MINUTE = 60 * 1000; 1838 /** 1839 * Number of milliseconds in a standard hour. 1840 * 1841 * @deprecated Use MILLIS_PER_HOUR. This will be removed in Commons Lang 3.0. 1842 */ 1843 public static final int MILLIS_IN_HOUR = 60 * 60 * 1000; 1844 /** 1845 * Number of milliseconds in a standard day. 1846 * 1847 * @deprecated Use MILLIS_PER_DAY. This will be removed in Commons Lang 3.0. 1848 */ 1849 public static final int MILLIS_IN_DAY = 24 * 60 * 60 * 1000; 1850 1851 }