001: /* ====================================================================
002: * The LateralNZ Software License, Version 1.0
003: *
004: * Copyright (c) 2003 LateralNZ. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by
021: * LateralNZ (http://www.lateralnz.org/) and other third parties."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. The names "LateralNZ" must not be used to endorse or promote
026: * products derived from this software without prior written
027: * permission. For written permission, please
028: * contact oss@lateralnz.org.
029: *
030: * 5. Products derived from this software may not be called "Panther",
031: * or "Lateral" or "LateralNZ", nor may "PANTHER" or "LATERAL" or
032: * "LATERALNZ" appear in their name, without prior written
033: * permission of LateralNZ.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of LateralNZ. For more
051: * information on Lateral, please see http://www.lateralnz.com/ or
052: * http://www.lateralnz.org
053: *
054: */
055: package org.lateralnz.common.util;
056:
057: import java.util.ArrayList;
058: import java.util.Calendar;
059: import java.util.Date;
060: import java.util.HashMap;
061: import java.util.List;
062: import java.util.Locale;
063: import java.text.ParseException;
064: import java.text.SimpleDateFormat;
065:
066: /**
067: * date formatting utilities
068: *
069: * @author J R Briggs
070: */
071: public final class DateUtils implements Constants {
072: private static final String CLASSNAME = DateUtils.class.getName();
073:
074: /**
075: * a constant representing "Mon"
076: */
077: public static final String MON = "Mon";
078:
079: /**
080: * a constant representing "Tues"
081: */
082: public static final String TUES = "Tues";
083:
084: /**
085: * a constant representing "Wed"
086: */
087: public static final String WED = "Wed";
088:
089: /**
090: * a constant representing "Thurs"
091: */
092: public static final String THURS = "Thurs";
093:
094: /**
095: * a constant representing "Fri"
096: */
097: public static final String FRI = "Fri";
098:
099: /**
100: * a constant representing "Sat"
101: */
102: public static final String SAT = "Sat";
103:
104: /**
105: * a constant representing "Sun"
106: */
107: public static final String SUN = "Sun";
108:
109: /**
110: * a constant format string for the day
111: */
112: public static final String DAY_DATE_FORMAT = "dd";
113:
114: /**
115: * a constant format string for the month
116: */
117: public static final String MONTH_DATE_FORMAT = "MM";
118:
119: /**
120: * a constant format string for the year
121: */
122: public static final String YEAR_DATE_FORMAT = "yyyy";
123:
124: /**
125: * a constant format string for the reverse data (yyyyMMdd)
126: */
127: public static final String REVERSE_DATE_FORMAT = "yyyyMMdd";
128:
129: /**
130: * a constant format string for the date and tim (yyyyMMddhhmmss)
131: */
132: public static final String REVERSE_DATE_TIME_FORMAT = REVERSE_DATE_FORMAT
133: + "HHmmss";
134:
135: /**
136: * a constant for the number of milliseconds in a day
137: */
138: public static final long ONE_DAY_IN_MILLISECONDS = 1000 * 60 * 60 * 24;
139:
140: private static HashMap dateFormats = new HashMap();
141:
142: /**
143: * a constant representing the beginning of time (or 01/01/0001)
144: */
145: public static Date BEGINNING_OF_TIME;
146:
147: /**
148: * a constant representing the end of time (or 31/12/9999)
149: */
150: public static Date END_OF_TIME;
151:
152: static {
153: try {
154: SimpleDateFormat tmp = new SimpleDateFormat(
155: REVERSE_DATE_FORMAT);
156: BEGINNING_OF_TIME = tmp.parse("00010101");
157: END_OF_TIME = tmp.parse("99991231");
158: } catch (Exception e) {
159: e.printStackTrace();
160: }
161: }
162:
163: private DateUtils() {
164: }
165:
166: /**
167: * add a value to a particular field (ie. day, month, year) of a date. Note: if you
168: * want to subtract, then add -1, -2, etc
169: * @param date the date object to add to
170: * @param field the field of the date (see Calendar for fields)
171: * @param amount the amount to add (or subtract if a negative number)
172: * @return a new date object
173: */
174: public static final Date add(Date date, int field, int amount) {
175: Calendar c = Calendar.getInstance();
176:
177: c.setTime(date);
178:
179: c.add(field, amount);
180:
181: return c.getTime();
182: }
183:
184: /**
185: * add a number of days to a date (basically a wrapper call to "add")
186: */
187: public static final Date addDays(Date date, int days) {
188: return add(date, Calendar.DATE, days);
189: }
190:
191: /**
192: * apply a string time value to a date object
193: * @param d the date object to apply time to
194: * @param time the time to apply as one of "hh", "hhmm" or "hhmmss"
195: */
196: public static final Date applyTime(Date d, String time) {
197: if (time.length() < 6) {
198: time = StringUtils.rpad(time, '0', 6);
199: }
200: Calendar c = Calendar.getInstance();
201:
202: c.setTime(d);
203:
204: c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(time.substring(0,
205: 2)));
206: c.set(Calendar.MINUTE, Integer.parseInt(time.substring(2, 4)));
207: c.set(Calendar.SECOND, Integer.parseInt(time.substring(4, 6)));
208: return c.getTime();
209: }
210:
211: /**
212: * Get a string representation of the month+year of current date.
213: * For instance, if it's "15/07/2003", this method returns "072003".
214: */
215: public static final String getCurrentMonthAsString() {
216: Calendar clen = Calendar.getInstance();
217: int month = clen.get(Calendar.MONTH);
218: int year = clen.get(Calendar.YEAR);
219:
220: String m = EMPTY;
221: String y = EMPTY + year;
222:
223: if (month < 10) {
224: m += "0" + month;
225: } else {
226: m += month;
227: }
228:
229: return m + y;
230: }
231:
232: /**
233: * get a list of date objects starting from 'start' and finishing -before- 'end'.
234: * Note: start must be after end
235: * @param start the date to start with
236: * @param end the date to end with
237: */
238: public static final List getDateRangeList(Date start, Date end) {
239: ArrayList rtn = new ArrayList();
240: Calendar c = Calendar.getInstance();
241: c.setTime(start);
242: while (c.getTime().before(end)) {
243: rtn.add(c.getTime());
244: c.add(Calendar.DATE, 1);
245: }
246:
247: return rtn;
248: }
249:
250: public static final int getDaysBetween(Date d1, Date d2) {
251: return (int) Math.abs((d1.getTime() - d2.getTime()) / 86400000);
252:
253: }
254:
255: /**
256: * get a string representation of a day of week (eg. "Mon", "Tues", etc)
257: * @return a string representation of the day
258: */
259: public static final String getShortDay(int dayOfWeek) {
260: switch (dayOfWeek) {
261: case Calendar.MONDAY:
262: return MON;
263: case Calendar.TUESDAY:
264: return TUES;
265: case Calendar.WEDNESDAY:
266: return WED;
267: case Calendar.THURSDAY:
268: return THURS;
269: case Calendar.FRIDAY:
270: return FRI;
271: case Calendar.SATURDAY:
272: return SAT;
273: case Calendar.SUNDAY:
274: return SUN;
275: default:
276: return EMPTY;
277: }
278: }
279:
280: /**
281: * get a string representation of the day of the week the specified date represents
282: * @param date the date object to use
283: */
284: public static final String getShortDay(Date date) {
285: Calendar c = Calendar.getInstance();
286: c.setTime(date);
287: int day = c.get(Calendar.DAY_OF_WEEK);
288: return getShortDay(day);
289: }
290:
291: /**
292: * get the first day of the week based upon the specified date (looks backwards from the
293: * date specified until it finds the monday)
294: * @returns a date object for the first day of the week
295: */
296: public static final Date getStartOfWeek(Date d) {
297: Calendar c = Calendar.getInstance();
298: c.setTime(d);
299: while (c.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
300: c.add(Calendar.DATE, -1);
301: }
302: return c.getTime();
303: }
304:
305: /**
306: * loads and caches a simpledateformat object
307: */
308: private static final SimpleDateFormat getFormat(String className,
309: String pattern, Locale locale) {
310: SimpleDateFormat format;
311: String key = className + UNDERSCORE + pattern + UNDERSCORE
312: + (locale != null ? locale.toString() : EMPTY);
313: if (!dateFormats.containsKey(key)) {
314: if (locale != null) {
315: format = new SimpleDateFormat(pattern, locale);
316: } else {
317: format = new SimpleDateFormat(pattern);
318: }
319:
320: synchronized (dateFormats) {
321: if (!dateFormats.containsKey(key)) {
322: dateFormats.put(key, format);
323: }
324: }
325: } else {
326: format = (SimpleDateFormat) dateFormats.get(key);
327: }
328:
329: return format;
330: }
331:
332: /**
333: * converts a date object into a string representation using a cached simpledateformat
334: * @param callerClassName the class of the object calling this method (used for caching)
335: * @param d the date to convert
336: * @param pattern the date format to use
337: */
338: public static final String formatDate(String callerClassName,
339: Date d, String pattern) {
340: return formatDate(callerClassName, d, null, pattern);
341: }
342:
343: /**
344: * converts a date object into a string representation using a cached simpledateformat
345: * @param callerClassName the class of the object calling this method (used for caching)
346: * @param d the date to convert
347: * @param locale the locale to use in conversion
348: * @param pattern the date format to use
349: */
350: public static final String formatDate(String callerClassName,
351: Date d, Locale locale, String pattern) {
352: if (d == null) {
353: return EMPTY;
354: }
355:
356: SimpleDateFormat format = getFormat(callerClassName, pattern,
357: locale);
358: synchronized (format) {
359: return format.format(d);
360: }
361: }
362:
363: /**
364: * turns a string representation of a date into a date object using a cached format
365: * @param callerClassName the class of the object calling this method (used for caching)
366: * @param s the string date to convert
367: * @param pattern the date format to use
368: */
369: public static final Date parseDate(String callerClassName,
370: String s, String pattern) throws ParseException {
371: return parseDate(callerClassName, s, null, pattern);
372: }
373:
374: /**
375: * turns a string representation of a date into a date object using a cached format
376: * @param callerClassName the class of the object calling this method (used for caching)
377: * @param s the string date to convert
378: * @param locale the locale to use in conversion
379: * @param pattern the date format to use
380: */
381: public static final Date parseDate(String callerClassName,
382: String s, Locale locale, String pattern)
383: throws ParseException {
384: if (StringUtils.isEmpty(s)) {
385: return null;
386: }
387:
388: SimpleDateFormat format = getFormat(callerClassName, pattern,
389: locale);
390: synchronized (format) {
391: return format.parse(s);
392: }
393: }
394:
395: /**
396: * returns true if two dates are equal using a particular date pattern
397: * @param callerClassName the class of the object calling this method (used for caching)
398: * @param d1 the first date
399: * @param d2 the second date
400: * @param pattern the date format to compare the two date objects by
401: */
402: public static final boolean isEqualUsingPattern(
403: String callerClassName, Date d1, Date d2, String pattern)
404: throws ParseException {
405: return isEqualUsingPattern(callerClassName, d1, d2, null,
406: pattern);
407: }
408:
409: /**
410: * returns true if two dates are equal using a particular date pattern
411: * @param callerClassName the class of the object calling this method (used for caching)
412: * @param d1 the first date
413: * @param d2 the second date
414: * @param locale the locale to use when comparing the dates
415: * @param pattern the date format to compare the two date objects by
416: */
417: public static final boolean isEqualUsingPattern(
418: String callerClassName, Date d1, Date d2, Locale locale,
419: String pattern) throws ParseException {
420: if (d1 == null || d2 == null) {
421: return false;
422: }
423:
424: String s1 = formatDate(callerClassName, d1, locale, pattern);
425: String s2 = formatDate(callerClassName, d2, locale, pattern);
426:
427: Date dn1 = parseDate(callerClassName, s1, locale, pattern);
428: Date dn2 = parseDate(callerClassName, s2, locale, pattern);
429:
430: return dn1.equals(dn2);
431: }
432:
433: /**
434: * takes a date object and sets a time value against it
435: * @param callerClassName the class of the object calling this method (used for caching)
436: * @param d the date object to use
437: * @param time the string representation of the time to set on the date object
438: * @param timeformat the format of the time
439: * @returns a new date object with the time set
440: */
441: public static final Date setTime(String callerClassName, Date d,
442: String time, String timeformat) throws ParseException {
443: String s = formatDate(callerClassName, d, REVERSE_DATE_FORMAT)
444: + time;
445: return parseDate(callerClassName, s, REVERSE_DATE_FORMAT
446: + timeformat);
447: }
448:
449: }
|