Source Code Cross Referenced for DateUtils.java in  » Library » Apache-common-lang » org » apache » commons » lang » time » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache common lang » org.apache.commons.lang.time 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         * 
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         * 
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:        package org.apache.commons.lang.time;
0018:
0019:        import java.text.ParseException;
0020:        import java.text.ParsePosition;
0021:        import java.text.SimpleDateFormat;
0022:        import java.util.Calendar;
0023:        import java.util.Date;
0024:        import java.util.Iterator;
0025:        import java.util.NoSuchElementException;
0026:        import java.util.TimeZone;
0027:
0028:        /**
0029:         * <p>A suite of utilities surrounding the use of the
0030:         * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
0031:         *
0032:         * @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
0033:         * @author Stephen Colebourne
0034:         * @author Janek Bogucki
0035:         * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
0036:         * @author Phil Steitz
0037:         * @since 2.0
0038:         * @version $Id: DateUtils.java 437554 2006-08-28 06:21:41Z bayard $
0039:         */
0040:        public class DateUtils {
0041:
0042:            /**
0043:             * The UTC time zone  (often referred to as GMT).
0044:             */
0045:            public static final TimeZone UTC_TIME_ZONE = TimeZone
0046:                    .getTimeZone("GMT");
0047:            /**
0048:             * Number of milliseconds in a standard second.
0049:             * @since 2.1
0050:             */
0051:            public static final long MILLIS_PER_SECOND = 1000;
0052:            /**
0053:             * Number of milliseconds in a standard minute.
0054:             * @since 2.1
0055:             */
0056:            public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
0057:            /**
0058:             * Number of milliseconds in a standard hour.
0059:             * @since 2.1
0060:             */
0061:            public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
0062:            /**
0063:             * Number of milliseconds in a standard day.
0064:             * @since 2.1
0065:             */
0066:            public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
0067:
0068:            /**
0069:             * This is half a month, so this represents whether a date is in the top
0070:             * or bottom half of the month.
0071:             */
0072:            public final static int SEMI_MONTH = 1001;
0073:
0074:            private static final int[][] fields = { { Calendar.MILLISECOND },
0075:                    { Calendar.SECOND }, { Calendar.MINUTE },
0076:                    { Calendar.HOUR_OF_DAY, Calendar.HOUR },
0077:                    { Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM
0078:                    /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */
0079:                    }, { Calendar.MONTH, DateUtils.SEMI_MONTH },
0080:                    { Calendar.YEAR }, { Calendar.ERA } };
0081:
0082:            /**
0083:             * A week range, starting on Sunday.
0084:             */
0085:            public final static int RANGE_WEEK_SUNDAY = 1;
0086:
0087:            /**
0088:             * A week range, starting on Monday.
0089:             */
0090:            public final static int RANGE_WEEK_MONDAY = 2;
0091:
0092:            /**
0093:             * A week range, starting on the day focused.
0094:             */
0095:            public final static int RANGE_WEEK_RELATIVE = 3;
0096:
0097:            /**
0098:             * A week range, centered around the day focused.
0099:             */
0100:            public final static int RANGE_WEEK_CENTER = 4;
0101:
0102:            /**
0103:             * A month range, the week starting on Sunday.
0104:             */
0105:            public final static int RANGE_MONTH_SUNDAY = 5;
0106:
0107:            /**
0108:             * A month range, the week starting on Monday.
0109:             */
0110:            public final static int RANGE_MONTH_MONDAY = 6;
0111:
0112:            /**
0113:             * <p><code>DateUtils</code> instances should NOT be constructed in
0114:             * standard programming. Instead, the class should be used as
0115:             * <code>DateUtils.parse(str);</code>.</p>
0116:             *
0117:             * <p>This constructor is public to permit tools that require a JavaBean
0118:             * instance to operate.</p>
0119:             */
0120:            public DateUtils() {
0121:                super ();
0122:            }
0123:
0124:            //-----------------------------------------------------------------------
0125:            /**
0126:             * <p>Checks if two date objects are on the same day ignoring time.</p>
0127:             *
0128:             * <p>28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true.
0129:             * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false.
0130:             * </p>
0131:             * 
0132:             * @param date1  the first date, not altered, not null
0133:             * @param date2  the second date, not altered, not null
0134:             * @return true if they represent the same day
0135:             * @throws IllegalArgumentException if either date is <code>null</code>
0136:             * @since 2.1
0137:             */
0138:            public static boolean isSameDay(Date date1, Date date2) {
0139:                if (date1 == null || date2 == null) {
0140:                    throw new IllegalArgumentException(
0141:                            "The date must not be null");
0142:                }
0143:                Calendar cal1 = Calendar.getInstance();
0144:                cal1.setTime(date1);
0145:                Calendar cal2 = Calendar.getInstance();
0146:                cal2.setTime(date2);
0147:                return isSameDay(cal1, cal2);
0148:            }
0149:
0150:            /**
0151:             * <p>Checks if two calendar objects are on the same day ignoring time.</p>
0152:             *
0153:             * <p>28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true.
0154:             * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false.
0155:             * </p>
0156:             * 
0157:             * @param cal1  the first calendar, not altered, not null
0158:             * @param cal2  the second calendar, not altered, not null
0159:             * @return true if they represent the same day
0160:             * @throws IllegalArgumentException if either calendar is <code>null</code>
0161:             * @since 2.1
0162:             */
0163:            public static boolean isSameDay(Calendar cal1, Calendar cal2) {
0164:                if (cal1 == null || cal2 == null) {
0165:                    throw new IllegalArgumentException(
0166:                            "The date must not be null");
0167:                }
0168:                return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA)
0169:                        && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1
0170:                        .get(Calendar.DAY_OF_YEAR) == cal2
0171:                        .get(Calendar.DAY_OF_YEAR));
0172:            }
0173:
0174:            //-----------------------------------------------------------------------
0175:            /**
0176:             * <p>Checks if two date objects represent the same instant in time.</p>
0177:             *
0178:             * <p>This method compares the long millisecond time of the two objects.</p>
0179:             * 
0180:             * @param date1  the first date, not altered, not null
0181:             * @param date2  the second date, not altered, not null
0182:             * @return true if they represent the same millisecond instant
0183:             * @throws IllegalArgumentException if either date is <code>null</code>
0184:             * @since 2.1
0185:             */
0186:            public static boolean isSameInstant(Date date1, Date date2) {
0187:                if (date1 == null || date2 == null) {
0188:                    throw new IllegalArgumentException(
0189:                            "The date must not be null");
0190:                }
0191:                return date1.getTime() == date2.getTime();
0192:            }
0193:
0194:            /**
0195:             * <p>Checks if two calendar objects represent the same instant in time.</p>
0196:             *
0197:             * <p>This method compares the long millisecond time of the two objects.</p>
0198:             * 
0199:             * @param cal1  the first calendar, not altered, not null
0200:             * @param cal2  the second calendar, not altered, not null
0201:             * @return true if they represent the same millisecond instant
0202:             * @throws IllegalArgumentException if either date is <code>null</code>
0203:             * @since 2.1
0204:             */
0205:            public static boolean isSameInstant(Calendar cal1, Calendar cal2) {
0206:                if (cal1 == null || cal2 == null) {
0207:                    throw new IllegalArgumentException(
0208:                            "The date must not be null");
0209:                }
0210:                return cal1.getTime().getTime() == cal2.getTime().getTime();
0211:            }
0212:
0213:            //-----------------------------------------------------------------------
0214:            /**
0215:             * <p>Checks if two calendar objects represent the same local time.</p>
0216:             *
0217:             * <p>This method compares the values of the fields of the two objects.
0218:             * In addition, both calendars must be the same of the same type.</p>
0219:             * 
0220:             * @param cal1  the first calendar, not altered, not null
0221:             * @param cal2  the second calendar, not altered, not null
0222:             * @return true if they represent the same millisecond instant
0223:             * @throws IllegalArgumentException if either date is <code>null</code>
0224:             * @since 2.1
0225:             */
0226:            public static boolean isSameLocalTime(Calendar cal1, Calendar cal2) {
0227:                if (cal1 == null || cal2 == null) {
0228:                    throw new IllegalArgumentException(
0229:                            "The date must not be null");
0230:                }
0231:                return (cal1.get(Calendar.MILLISECOND) == cal2
0232:                        .get(Calendar.MILLISECOND)
0233:                        && cal1.get(Calendar.SECOND) == cal2
0234:                                .get(Calendar.SECOND)
0235:                        && cal1.get(Calendar.MINUTE) == cal2
0236:                                .get(Calendar.MINUTE)
0237:                        && cal1.get(Calendar.HOUR) == cal2.get(Calendar.HOUR)
0238:                        && cal1.get(Calendar.DAY_OF_YEAR) == cal2
0239:                                .get(Calendar.DAY_OF_YEAR)
0240:                        && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
0241:                        && cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1
0242:                        .getClass() == cal2.getClass());
0243:            }
0244:
0245:            //-----------------------------------------------------------------------
0246:            /**
0247:             * <p>Parses a string representing a date by trying a variety of different parsers.</p>
0248:             * 
0249:             * <p>The parse will try each parse pattern in turn.
0250:             * A parse is only deemed sucessful if it parses the whole of the input string.
0251:             * If no parse patterns match, a ParseException is thrown.</p>
0252:             * 
0253:             * @param str  the date to parse, not null
0254:             * @param parsePatterns  the date format patterns to use, see SimpleDateFormat, not null
0255:             * @return the parsed date
0256:             * @throws IllegalArgumentException if the date string or pattern array is null
0257:             * @throws ParseException if none of the date patterns were suitable
0258:             */
0259:            public static Date parseDate(String str, String[] parsePatterns)
0260:                    throws ParseException {
0261:                if (str == null || parsePatterns == null) {
0262:                    throw new IllegalArgumentException(
0263:                            "Date and Patterns must not be null");
0264:                }
0265:
0266:                SimpleDateFormat parser = null;
0267:                ParsePosition pos = new ParsePosition(0);
0268:                for (int i = 0; i < parsePatterns.length; i++) {
0269:                    if (i == 0) {
0270:                        parser = new SimpleDateFormat(parsePatterns[0]);
0271:                    } else {
0272:                        parser.applyPattern(parsePatterns[i]);
0273:                    }
0274:                    pos.setIndex(0);
0275:                    Date date = parser.parse(str, pos);
0276:                    if (date != null && pos.getIndex() == str.length()) {
0277:                        return date;
0278:                    }
0279:                }
0280:                throw new ParseException("Unable to parse the date: " + str, -1);
0281:            }
0282:
0283:            //-----------------------------------------------------------------------
0284:            /**
0285:             * Adds a number of years to a date returning a new object.
0286:             * The original date object is unchanged.
0287:             *
0288:             * @param date  the date, not null
0289:             * @param amount  the amount to add, may be negative
0290:             * @return the new date object with the amount added
0291:             * @throws IllegalArgumentException if the date is null
0292:             */
0293:            public static Date addYears(Date date, int amount) {
0294:                return add(date, Calendar.YEAR, amount);
0295:            }
0296:
0297:            //-----------------------------------------------------------------------
0298:            /**
0299:             * Adds a number of months to a date returning a new object.
0300:             * The original date object is unchanged.
0301:             *
0302:             * @param date  the date, not null
0303:             * @param amount  the amount to add, may be negative
0304:             * @return the new date object with the amount added
0305:             * @throws IllegalArgumentException if the date is null
0306:             */
0307:            public static Date addMonths(Date date, int amount) {
0308:                return add(date, Calendar.MONTH, amount);
0309:            }
0310:
0311:            //-----------------------------------------------------------------------
0312:            /**
0313:             * Adds a number of weeks to a date returning a new object.
0314:             * The original date object is unchanged.
0315:             *
0316:             * @param date  the date, not null
0317:             * @param amount  the amount to add, may be negative
0318:             * @return the new date object with the amount added
0319:             * @throws IllegalArgumentException if the date is null
0320:             */
0321:            public static Date addWeeks(Date date, int amount) {
0322:                return add(date, Calendar.WEEK_OF_YEAR, amount);
0323:            }
0324:
0325:            //-----------------------------------------------------------------------
0326:            /**
0327:             * Adds a number of days to a date returning a new object.
0328:             * The original date object is unchanged.
0329:             *
0330:             * @param date  the date, not null
0331:             * @param amount  the amount to add, may be negative
0332:             * @return the new date object with the amount added
0333:             * @throws IllegalArgumentException if the date is null
0334:             */
0335:            public static Date addDays(Date date, int amount) {
0336:                return add(date, Calendar.DAY_OF_MONTH, amount);
0337:            }
0338:
0339:            //-----------------------------------------------------------------------
0340:            /**
0341:             * Adds a number of hours to a date returning a new object.
0342:             * The original date object is unchanged.
0343:             *
0344:             * @param date  the date, not null
0345:             * @param amount  the amount to add, may be negative
0346:             * @return the new date object with the amount added
0347:             * @throws IllegalArgumentException if the date is null
0348:             */
0349:            public static Date addHours(Date date, int amount) {
0350:                return add(date, Calendar.HOUR_OF_DAY, amount);
0351:            }
0352:
0353:            //-----------------------------------------------------------------------
0354:            /**
0355:             * Adds a number of minutes to a date returning a new object.
0356:             * The original date object is unchanged.
0357:             *
0358:             * @param date  the date, not null
0359:             * @param amount  the amount to add, may be negative
0360:             * @return the new date object with the amount added
0361:             * @throws IllegalArgumentException if the date is null
0362:             */
0363:            public static Date addMinutes(Date date, int amount) {
0364:                return add(date, Calendar.MINUTE, amount);
0365:            }
0366:
0367:            //-----------------------------------------------------------------------
0368:            /**
0369:             * Adds a number of seconds to a date returning a new object.
0370:             * The original date object is unchanged.
0371:             *
0372:             * @param date  the date, not null
0373:             * @param amount  the amount to add, may be negative
0374:             * @return the new date object with the amount added
0375:             * @throws IllegalArgumentException if the date is null
0376:             */
0377:            public static Date addSeconds(Date date, int amount) {
0378:                return add(date, Calendar.SECOND, amount);
0379:            }
0380:
0381:            //-----------------------------------------------------------------------
0382:            /**
0383:             * Adds a number of milliseconds to a date returning a new object.
0384:             * The original date object is unchanged.
0385:             *
0386:             * @param date  the date, not null
0387:             * @param amount  the amount to add, may be negative
0388:             * @return the new date object with the amount added
0389:             * @throws IllegalArgumentException if the date is null
0390:             */
0391:            public static Date addMilliseconds(Date date, int amount) {
0392:                return add(date, Calendar.MILLISECOND, amount);
0393:            }
0394:
0395:            //-----------------------------------------------------------------------
0396:            /**
0397:             * Adds to a date returning a new object.
0398:             * The original date object is unchanged.
0399:             *
0400:             * @param date  the date, not null
0401:             * @param calendarField  the calendar field to add to
0402:             * @param amount  the amount to add, may be negative
0403:             * @return the new date object with the amount added
0404:             * @throws IllegalArgumentException if the date is null
0405:             */
0406:            public static Date add(Date date, int calendarField, int amount) {
0407:                if (date == null) {
0408:                    throw new IllegalArgumentException(
0409:                            "The date must not be null");
0410:                }
0411:                Calendar c = Calendar.getInstance();
0412:                c.setTime(date);
0413:                c.add(calendarField, amount);
0414:                return c.getTime();
0415:            }
0416:
0417:            //-----------------------------------------------------------------------
0418:            /**
0419:             * <p>Round this date, leaving the field specified as the most
0420:             * significant field.</p>
0421:             *
0422:             * <p>For example, if you had the datetime of 28 Mar 2002
0423:             * 13:45:01.231, if this was passed with HOUR, it would return
0424:             * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it
0425:             * would return 1 April 2002 0:00:00.000.</p>
0426:             * 
0427:             * <p>For a date in a timezone that handles the change to daylight
0428:             * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows.
0429:             * Suppose daylight saving time begins at 02:00 on March 30. Rounding a 
0430:             * date that crosses this time would produce the following values:
0431:             * <ul>
0432:             * <li>March 30, 2003 01:10 rounds to March 30, 2003 01:00</li>
0433:             * <li>March 30, 2003 01:40 rounds to March 30, 2003 03:00</li>
0434:             * <li>March 30, 2003 02:10 rounds to March 30, 2003 03:00</li>
0435:             * <li>March 30, 2003 02:40 rounds to March 30, 2003 04:00</li>
0436:             * </ul>
0437:             * </p>
0438:             * 
0439:             * @param date  the date to work with
0440:             * @param field  the field from <code>Calendar</code>
0441:             *  or <code>SEMI_MONTH</code>
0442:             * @return the rounded date
0443:             * @throws IllegalArgumentException if the date is <code>null</code>
0444:             * @throws ArithmeticException if the year is over 280 million
0445:             */
0446:            public static Date round(Date date, int field) {
0447:                if (date == null) {
0448:                    throw new IllegalArgumentException(
0449:                            "The date must not be null");
0450:                }
0451:                Calendar gval = Calendar.getInstance();
0452:                gval.setTime(date);
0453:                modify(gval, field, true);
0454:                return gval.getTime();
0455:            }
0456:
0457:            /**
0458:             * <p>Round this date, leaving the field specified as the most
0459:             * significant field.</p>
0460:             *
0461:             * <p>For example, if you had the datetime of 28 Mar 2002
0462:             * 13:45:01.231, if this was passed with HOUR, it would return
0463:             * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it
0464:             * would return 1 April 2002 0:00:00.000.</p>
0465:             * 
0466:             * <p>For a date in a timezone that handles the change to daylight
0467:             * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows.
0468:             * Suppose daylight saving time begins at 02:00 on March 30. Rounding a 
0469:             * date that crosses this time would produce the following values:
0470:             * <ul>
0471:             * <li>March 30, 2003 01:10 rounds to March 30, 2003 01:00</li>
0472:             * <li>March 30, 2003 01:40 rounds to March 30, 2003 03:00</li>
0473:             * <li>March 30, 2003 02:10 rounds to March 30, 2003 03:00</li>
0474:             * <li>March 30, 2003 02:40 rounds to March 30, 2003 04:00</li>
0475:             * </ul>
0476:             * </p>
0477:             * 
0478:             * @param date  the date to work with
0479:             * @param field  the field from <code>Calendar</code>
0480:             *  or <code>SEMI_MONTH</code>
0481:             * @return the rounded date (a different object)
0482:             * @throws IllegalArgumentException if the date is <code>null</code>
0483:             * @throws ArithmeticException if the year is over 280 million
0484:             */
0485:            public static Calendar round(Calendar date, int field) {
0486:                if (date == null) {
0487:                    throw new IllegalArgumentException(
0488:                            "The date must not be null");
0489:                }
0490:                Calendar rounded = (Calendar) date.clone();
0491:                modify(rounded, field, true);
0492:                return rounded;
0493:            }
0494:
0495:            /**
0496:             * <p>Round this date, leaving the field specified as the most
0497:             * significant field.</p>
0498:             *
0499:             * <p>For example, if you had the datetime of 28 Mar 2002
0500:             * 13:45:01.231, if this was passed with HOUR, it would return
0501:             * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it
0502:             * would return 1 April 2002 0:00:00.000.</p>
0503:             * 
0504:             * <p>For a date in a timezone that handles the change to daylight
0505:             * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows.
0506:             * Suppose daylight saving time begins at 02:00 on March 30. Rounding a 
0507:             * date that crosses this time would produce the following values:
0508:             * <ul>
0509:             * <li>March 30, 2003 01:10 rounds to March 30, 2003 01:00</li>
0510:             * <li>March 30, 2003 01:40 rounds to March 30, 2003 03:00</li>
0511:             * <li>March 30, 2003 02:10 rounds to March 30, 2003 03:00</li>
0512:             * <li>March 30, 2003 02:40 rounds to March 30, 2003 04:00</li>
0513:             * </ul>
0514:             * </p>
0515:             * 
0516:             * @param date  the date to work with, either Date or Calendar
0517:             * @param field  the field from <code>Calendar</code>
0518:             *  or <code>SEMI_MONTH</code>
0519:             * @return the rounded date
0520:             * @throws IllegalArgumentException if the date is <code>null</code>
0521:             * @throws ClassCastException if the object type is not a <code>Date</code>
0522:             *  or <code>Calendar</code>
0523:             * @throws ArithmeticException if the year is over 280 million
0524:             */
0525:            public static Date round(Object date, int field) {
0526:                if (date == null) {
0527:                    throw new IllegalArgumentException(
0528:                            "The date must not be null");
0529:                }
0530:                if (date instanceof  Date) {
0531:                    return round((Date) date, field);
0532:                } else if (date instanceof  Calendar) {
0533:                    return round((Calendar) date, field).getTime();
0534:                } else {
0535:                    throw new ClassCastException("Could not round " + date);
0536:                }
0537:            }
0538:
0539:            //-----------------------------------------------------------------------
0540:            /**
0541:             * <p>Truncate this date, leaving the field specified as the most
0542:             * significant field.</p>
0543:             *
0544:             * <p>For example, if you had the datetime of 28 Mar 2002
0545:             * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
0546:             * 2002 13:00:00.000.  If this was passed with MONTH, it would
0547:             * return 1 Mar 2002 0:00:00.000.</p>
0548:             * 
0549:             * @param date  the date to work with
0550:             * @param field  the field from <code>Calendar</code>
0551:             *  or <code>SEMI_MONTH</code>
0552:             * @return the rounded date
0553:             * @throws IllegalArgumentException if the date is <code>null</code>
0554:             * @throws ArithmeticException if the year is over 280 million
0555:             */
0556:            public static Date truncate(Date date, int field) {
0557:                if (date == null) {
0558:                    throw new IllegalArgumentException(
0559:                            "The date must not be null");
0560:                }
0561:                Calendar gval = Calendar.getInstance();
0562:                gval.setTime(date);
0563:                modify(gval, field, false);
0564:                return gval.getTime();
0565:            }
0566:
0567:            /**
0568:             * <p>Truncate this date, leaving the field specified as the most
0569:             * significant field.</p>
0570:             *
0571:             * <p>For example, if you had the datetime of 28 Mar 2002
0572:             * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
0573:             * 2002 13:00:00.000.  If this was passed with MONTH, it would
0574:             * return 1 Mar 2002 0:00:00.000.</p>
0575:             * 
0576:             * @param date  the date to work with
0577:             * @param field  the field from <code>Calendar</code>
0578:             *  or <code>SEMI_MONTH</code>
0579:             * @return the rounded date (a different object)
0580:             * @throws IllegalArgumentException if the date is <code>null</code>
0581:             * @throws ArithmeticException if the year is over 280 million
0582:             */
0583:            public static Calendar truncate(Calendar date, int field) {
0584:                if (date == null) {
0585:                    throw new IllegalArgumentException(
0586:                            "The date must not be null");
0587:                }
0588:                Calendar truncated = (Calendar) date.clone();
0589:                modify(truncated, field, false);
0590:                return truncated;
0591:            }
0592:
0593:            /**
0594:             * <p>Truncate this date, leaving the field specified as the most
0595:             * significant field.</p>
0596:             *
0597:             * <p>For example, if you had the datetime of 28 Mar 2002
0598:             * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
0599:             * 2002 13:00:00.000.  If this was passed with MONTH, it would
0600:             * return 1 Mar 2002 0:00:00.000.</p>
0601:             * 
0602:             * @param date  the date to work with, either <code>Date</code>
0603:             *  or <code>Calendar</code>
0604:             * @param field  the field from <code>Calendar</code>
0605:             *  or <code>SEMI_MONTH</code>
0606:             * @return the rounded date
0607:             * @throws IllegalArgumentException if the date
0608:             *  is <code>null</code>
0609:             * @throws ClassCastException if the object type is not a
0610:             *  <code>Date</code> or <code>Calendar</code>
0611:             * @throws ArithmeticException if the year is over 280 million
0612:             */
0613:            public static Date truncate(Object date, int field) {
0614:                if (date == null) {
0615:                    throw new IllegalArgumentException(
0616:                            "The date must not be null");
0617:                }
0618:                if (date instanceof  Date) {
0619:                    return truncate((Date) date, field);
0620:                } else if (date instanceof  Calendar) {
0621:                    return truncate((Calendar) date, field).getTime();
0622:                } else {
0623:                    throw new ClassCastException("Could not truncate " + date);
0624:                }
0625:            }
0626:
0627:            //-----------------------------------------------------------------------
0628:            /**
0629:             * <p>Internal calculation method.</p>
0630:             * 
0631:             * @param val  the calendar
0632:             * @param field  the field constant
0633:             * @param round  true to round, false to truncate
0634:             * @throws ArithmeticException if the year is over 280 million
0635:             */
0636:            private static void modify(Calendar val, int field, boolean round) {
0637:                if (val.get(Calendar.YEAR) > 280000000) {
0638:                    throw new ArithmeticException(
0639:                            "Calendar value too large for accurate calculations");
0640:                }
0641:
0642:                if (field == Calendar.MILLISECOND) {
0643:                    return;
0644:                }
0645:
0646:                // ----------------- Fix for LANG-59 ---------------------- START ---------------
0647:                // see http://issues.apache.org/jira/browse/LANG-59
0648:                //
0649:                // Manually truncate milliseconds, seconds and minutes, rather than using
0650:                // Calendar methods.
0651:
0652:                Date date = val.getTime();
0653:                long time = date.getTime();
0654:                boolean done = false;
0655:
0656:                // truncate milliseconds
0657:                int millisecs = val.get(Calendar.MILLISECOND);
0658:                if (!round || millisecs < 500) {
0659:                    time = time - millisecs;
0660:                    if (field == Calendar.SECOND) {
0661:                        done = true;
0662:                    }
0663:                }
0664:
0665:                // truncate seconds
0666:                int seconds = val.get(Calendar.SECOND);
0667:                if (!done && (!round || seconds < 30)) {
0668:                    time = time - (seconds * 1000L);
0669:                    if (field == Calendar.MINUTE) {
0670:                        done = true;
0671:                    }
0672:                }
0673:
0674:                // truncate minutes
0675:                int minutes = val.get(Calendar.MINUTE);
0676:                if (!done && (!round || minutes < 30)) {
0677:                    time = time - (minutes * 60000L);
0678:                }
0679:
0680:                // reset time
0681:                if (date.getTime() != time) {
0682:                    date.setTime(time);
0683:                    val.setTime(date);
0684:                }
0685:                // ----------------- Fix for LANG-59 ----------------------- END ----------------
0686:
0687:                boolean roundUp = false;
0688:                for (int i = 0; i < fields.length; i++) {
0689:                    for (int j = 0; j < fields[i].length; j++) {
0690:                        if (fields[i][j] == field) {
0691:                            //This is our field... we stop looping
0692:                            if (round && roundUp) {
0693:                                if (field == DateUtils.SEMI_MONTH) {
0694:                                    //This is a special case that's hard to generalize
0695:                                    //If the date is 1, we round up to 16, otherwise
0696:                                    //  we subtract 15 days and add 1 month
0697:                                    if (val.get(Calendar.DATE) == 1) {
0698:                                        val.add(Calendar.DATE, 15);
0699:                                    } else {
0700:                                        val.add(Calendar.DATE, -15);
0701:                                        val.add(Calendar.MONTH, 1);
0702:                                    }
0703:                                } else {
0704:                                    //We need at add one to this field since the
0705:                                    //  last number causes us to round up
0706:                                    val.add(fields[i][0], 1);
0707:                                }
0708:                            }
0709:                            return;
0710:                        }
0711:                    }
0712:                    //We have various fields that are not easy roundings
0713:                    int offset = 0;
0714:                    boolean offsetSet = false;
0715:                    //These are special types of fields that require different rounding rules
0716:                    switch (field) {
0717:                    case DateUtils.SEMI_MONTH:
0718:                        if (fields[i][0] == Calendar.DATE) {
0719:                            //If we're going to drop the DATE field's value,
0720:                            //  we want to do this our own way.
0721:                            //We need to subtrace 1 since the date has a minimum of 1
0722:                            offset = val.get(Calendar.DATE) - 1;
0723:                            //If we're above 15 days adjustment, that means we're in the
0724:                            //  bottom half of the month and should stay accordingly.
0725:                            if (offset >= 15) {
0726:                                offset -= 15;
0727:                            }
0728:                            //Record whether we're in the top or bottom half of that range
0729:                            roundUp = offset > 7;
0730:                            offsetSet = true;
0731:                        }
0732:                        break;
0733:                    case Calendar.AM_PM:
0734:                        if (fields[i][0] == Calendar.HOUR_OF_DAY) {
0735:                            //If we're going to drop the HOUR field's value,
0736:                            //  we want to do this our own way.
0737:                            offset = val.get(Calendar.HOUR_OF_DAY);
0738:                            if (offset >= 12) {
0739:                                offset -= 12;
0740:                            }
0741:                            roundUp = offset > 6;
0742:                            offsetSet = true;
0743:                        }
0744:                        break;
0745:                    }
0746:                    if (!offsetSet) {
0747:                        int min = val.getActualMinimum(fields[i][0]);
0748:                        int max = val.getActualMaximum(fields[i][0]);
0749:                        //Calculate the offset from the minimum allowed value
0750:                        offset = val.get(fields[i][0]) - min;
0751:                        //Set roundUp if this is more than half way between the minimum and maximum
0752:                        roundUp = offset > ((max - min) / 2);
0753:                    }
0754:                    //We need to remove this field
0755:                    if (offset != 0) {
0756:                        val.set(fields[i][0], val.get(fields[i][0]) - offset);
0757:                    }
0758:                }
0759:                throw new IllegalArgumentException("The field " + field
0760:                        + " is not supported");
0761:
0762:            }
0763:
0764:            //-----------------------------------------------------------------------
0765:            /**
0766:             * <p>This constructs an <code>Iterator</code> over each day in a date
0767:             * range defined by a focus date and range style.</p>
0768:             *
0769:             * <p>For instance, passing Thursday, July 4, 2002 and a
0770:             * <code>RANGE_MONTH_SUNDAY</code> will return an <code>Iterator</code>
0771:             * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
0772:             * 2002, returning a Calendar instance for each intermediate day.</p>
0773:             *
0774:             * <p>This method provides an iterator that returns Calendar objects.
0775:             * The days are progressed using {@link Calendar#add(int, int)}.</p>
0776:             *
0777:             * @param focus  the date to work with, not null
0778:             * @param rangeStyle  the style constant to use. Must be one of
0779:             * {@link DateUtils#RANGE_MONTH_SUNDAY}, 
0780:             * {@link DateUtils#RANGE_MONTH_MONDAY},
0781:             * {@link DateUtils#RANGE_WEEK_SUNDAY},
0782:             * {@link DateUtils#RANGE_WEEK_MONDAY},
0783:             * {@link DateUtils#RANGE_WEEK_RELATIVE},
0784:             * {@link DateUtils#RANGE_WEEK_CENTER}
0785:             * @return the date iterator, which always returns Calendar instances
0786:             * @throws IllegalArgumentException if the date is <code>null</code>
0787:             * @throws IllegalArgumentException if the rangeStyle is invalid
0788:             */
0789:            public static Iterator iterator(Date focus, int rangeStyle) {
0790:                if (focus == null) {
0791:                    throw new IllegalArgumentException(
0792:                            "The date must not be null");
0793:                }
0794:                Calendar gval = Calendar.getInstance();
0795:                gval.setTime(focus);
0796:                return iterator(gval, rangeStyle);
0797:            }
0798:
0799:            /**
0800:             * <p>This constructs an <code>Iterator</code> over each day in a date
0801:             * range defined by a focus date and range style.</p>
0802:             *
0803:             * <p>For instance, passing Thursday, July 4, 2002 and a
0804:             * <code>RANGE_MONTH_SUNDAY</code> will return an <code>Iterator</code>
0805:             * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
0806:             * 2002, returning a Calendar instance for each intermediate day.</p>
0807:             *
0808:             * <p>This method provides an iterator that returns Calendar objects.
0809:             * The days are progressed using {@link Calendar#add(int, int)}.</p>
0810:             *
0811:             * @param focus  the date to work with
0812:             * @param rangeStyle  the style constant to use. Must be one of
0813:             * {@link DateUtils#RANGE_MONTH_SUNDAY}, 
0814:             * {@link DateUtils#RANGE_MONTH_MONDAY},
0815:             * {@link DateUtils#RANGE_WEEK_SUNDAY},
0816:             * {@link DateUtils#RANGE_WEEK_MONDAY},
0817:             * {@link DateUtils#RANGE_WEEK_RELATIVE},
0818:             * {@link DateUtils#RANGE_WEEK_CENTER}
0819:             * @return the date iterator
0820:             * @throws IllegalArgumentException if the date is <code>null</code>
0821:             * @throws IllegalArgumentException if the rangeStyle is invalid
0822:             */
0823:            public static Iterator iterator(Calendar focus, int rangeStyle) {
0824:                if (focus == null) {
0825:                    throw new IllegalArgumentException(
0826:                            "The date must not be null");
0827:                }
0828:                Calendar start = null;
0829:                Calendar end = null;
0830:                int startCutoff = Calendar.SUNDAY;
0831:                int endCutoff = Calendar.SATURDAY;
0832:                switch (rangeStyle) {
0833:                case RANGE_MONTH_SUNDAY:
0834:                case RANGE_MONTH_MONDAY:
0835:                    //Set start to the first of the month
0836:                    start = truncate(focus, Calendar.MONTH);
0837:                    //Set end to the last of the month
0838:                    end = (Calendar) start.clone();
0839:                    end.add(Calendar.MONTH, 1);
0840:                    end.add(Calendar.DATE, -1);
0841:                    //Loop start back to the previous sunday or monday
0842:                    if (rangeStyle == RANGE_MONTH_MONDAY) {
0843:                        startCutoff = Calendar.MONDAY;
0844:                        endCutoff = Calendar.SUNDAY;
0845:                    }
0846:                    break;
0847:                case RANGE_WEEK_SUNDAY:
0848:                case RANGE_WEEK_MONDAY:
0849:                case RANGE_WEEK_RELATIVE:
0850:                case RANGE_WEEK_CENTER:
0851:                    //Set start and end to the current date
0852:                    start = truncate(focus, Calendar.DATE);
0853:                    end = truncate(focus, Calendar.DATE);
0854:                    switch (rangeStyle) {
0855:                    case RANGE_WEEK_SUNDAY:
0856:                        //already set by default
0857:                        break;
0858:                    case RANGE_WEEK_MONDAY:
0859:                        startCutoff = Calendar.MONDAY;
0860:                        endCutoff = Calendar.SUNDAY;
0861:                        break;
0862:                    case RANGE_WEEK_RELATIVE:
0863:                        startCutoff = focus.get(Calendar.DAY_OF_WEEK);
0864:                        endCutoff = startCutoff - 1;
0865:                        break;
0866:                    case RANGE_WEEK_CENTER:
0867:                        startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3;
0868:                        endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3;
0869:                        break;
0870:                    }
0871:                    break;
0872:                default:
0873:                    throw new IllegalArgumentException("The range style "
0874:                            + rangeStyle + " is not valid.");
0875:                }
0876:                if (startCutoff < Calendar.SUNDAY) {
0877:                    startCutoff += 7;
0878:                }
0879:                if (startCutoff > Calendar.SATURDAY) {
0880:                    startCutoff -= 7;
0881:                }
0882:                if (endCutoff < Calendar.SUNDAY) {
0883:                    endCutoff += 7;
0884:                }
0885:                if (endCutoff > Calendar.SATURDAY) {
0886:                    endCutoff -= 7;
0887:                }
0888:                while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) {
0889:                    start.add(Calendar.DATE, -1);
0890:                }
0891:                while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) {
0892:                    end.add(Calendar.DATE, 1);
0893:                }
0894:                return new DateIterator(start, end);
0895:            }
0896:
0897:            /**
0898:             * <p>This constructs an <code>Iterator</code> over each day in a date
0899:             * range defined by a focus date and range style.</p>
0900:             *
0901:             * <p>For instance, passing Thursday, July 4, 2002 and a
0902:             * <code>RANGE_MONTH_SUNDAY</code> will return an <code>Iterator</code>
0903:             * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
0904:             * 2002, returning a Calendar instance for each intermediate day.</p>
0905:             *
0906:             * @param focus  the date to work with, either
0907:             *  <code>Date</code> or <code>Calendar</code>
0908:             * @param rangeStyle  the style constant to use. Must be one of the range
0909:             * styles listed for the {@link #iterator(Calendar, int)} method.
0910:             * @return the date iterator
0911:             * @throws IllegalArgumentException if the date
0912:             *  is <code>null</code>
0913:             * @throws ClassCastException if the object type is
0914:             *  not a <code>Date</code> or <code>Calendar</code>
0915:             */
0916:            public static Iterator iterator(Object focus, int rangeStyle) {
0917:                if (focus == null) {
0918:                    throw new IllegalArgumentException(
0919:                            "The date must not be null");
0920:                }
0921:                if (focus instanceof  Date) {
0922:                    return iterator((Date) focus, rangeStyle);
0923:                } else if (focus instanceof  Calendar) {
0924:                    return iterator((Calendar) focus, rangeStyle);
0925:                } else {
0926:                    throw new ClassCastException("Could not iterate based on "
0927:                            + focus);
0928:                }
0929:            }
0930:
0931:            /**
0932:             * <p>Date iterator.</p>
0933:             */
0934:            static class DateIterator implements  Iterator {
0935:                private final Calendar endFinal;
0936:                private final Calendar spot;
0937:
0938:                /**
0939:                 * Constructs a DateIterator that ranges from one date to another. 
0940:                 *
0941:                 * @param startFinal start date (inclusive)
0942:                 * @param endFinal end date (not inclusive)
0943:                 */
0944:                DateIterator(Calendar startFinal, Calendar endFinal) {
0945:                    super ();
0946:                    this .endFinal = endFinal;
0947:                    spot = startFinal;
0948:                    spot.add(Calendar.DATE, -1);
0949:                }
0950:
0951:                /**
0952:                 * Has the iterator not reached the end date yet?
0953:                 *
0954:                 * @return <code>true</code> if the iterator has yet to reach the end date
0955:                 */
0956:                public boolean hasNext() {
0957:                    return spot.before(endFinal);
0958:                }
0959:
0960:                /**
0961:                 * Return the next calendar in the iteration
0962:                 *
0963:                 * @return Object calendar for the next date
0964:                 */
0965:                public Object next() {
0966:                    if (spot.equals(endFinal)) {
0967:                        throw new NoSuchElementException();
0968:                    }
0969:                    spot.add(Calendar.DATE, 1);
0970:                    return spot.clone();
0971:                }
0972:
0973:                /**
0974:                 * Always throws UnsupportedOperationException.
0975:                 * 
0976:                 * @throws UnsupportedOperationException
0977:                 * @see java.util.Iterator#remove()
0978:                 */
0979:                public void remove() {
0980:                    throw new UnsupportedOperationException();
0981:                }
0982:            }
0983:
0984:            //------------------------------------------------------------------------- 
0985:            // Deprecated int constants
0986:            // TODO: Remove in 3.0
0987:
0988:            /**
0989:             * Number of milliseconds in a standard second.
0990:             * 
0991:             * @deprecated Use MILLIS_PER_SECOND. This will be removed in Commons Lang 3.0.
0992:             */
0993:            public static final int MILLIS_IN_SECOND = 1000;
0994:            /**
0995:             * Number of milliseconds in a standard minute.
0996:             * 
0997:             * @deprecated Use MILLIS_PER_MINUTE. This will be removed in Commons Lang 3.0.
0998:             */
0999:            public static final int MILLIS_IN_MINUTE = 60 * 1000;
1000:            /**
1001:             * Number of milliseconds in a standard hour.
1002:             * 
1003:             * @deprecated Use MILLIS_PER_HOUR. This will be removed in Commons Lang 3.0.
1004:             */
1005:            public static final int MILLIS_IN_HOUR = 60 * 60 * 1000;
1006:            /**
1007:             * Number of milliseconds in a standard day.
1008:             * 
1009:             * @deprecated Use MILLIS_PER_DAY. This will be removed in Commons Lang 3.0.
1010:             */
1011:            public static final int MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
1012:
1013:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.