001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. The ASF licenses this file to You
004: * under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License. For additional information regarding
015: * copyright in this work, please see the NOTICE file in the top level
016: * directory of this distribution.
017: */
018:
019: package org.apache.roller.util;
020:
021: import java.text.ParseException;
022: import java.text.ParsePosition;
023: import java.text.SimpleDateFormat;
024: import java.util.Calendar;
025: import java.util.Date;
026: import java.util.Locale;
027: import java.util.TimeZone;
028: import org.apache.commons.lang.StringUtils;
029:
030: /**
031: * General purpose date utilities.
032: */
033: public abstract class DateUtil {
034:
035: public static final long millisInDay = 86400000;
036:
037: // a bunch of date formats
038: private static final String formatDefaultDate = "dd.MM.yyyy";
039: private static final String formatDefaultDateMinimal = "d.M.yy";
040: private static final String formatDefaultTimestamp = "yyyy-MM-dd HH:mm:ss.SSS";
041:
042: private static final String formatFriendlyTimestamp = "dd.MM.yyyy HH:mm:ss";
043:
044: private static final String format6chars = "yyyyMM";
045: private static final String format8chars = "yyyyMMdd";
046:
047: private static final String formatIso8601 = "yyyy-MM-dd'T'HH:mm:ssZ";
048: private static final String formatIso8601Day = "yyyy-MM-dd";
049:
050: private static final String formatRfc822 = "EEE, d MMM yyyy HH:mm:ss Z";
051:
052: /**
053: * Returns a Date set to the last possible millisecond of the day, just
054: * before midnight. If a null day is passed in, a new Date is created.
055: * midnight (00m 00h 00s)
056: */
057: public static Date getEndOfDay(Date day) {
058: return getEndOfDay(day, Calendar.getInstance());
059: }
060:
061: public static Date getEndOfDay(Date day, Calendar cal) {
062: if (day == null)
063: day = new Date();
064: cal.setTime(day);
065: cal.set(Calendar.HOUR_OF_DAY, cal
066: .getMaximum(Calendar.HOUR_OF_DAY));
067: cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
068: cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
069: cal.set(Calendar.MILLISECOND, cal
070: .getMaximum(Calendar.MILLISECOND));
071: return cal.getTime();
072: }
073:
074: /**
075: * Returns a Date set to the last possible millisecond of the day, just
076: * before midnight. If a null day is passed in, a new Date is created.
077: * midnight (00m 00h 00s)
078: */
079: public static Date getEndOfHour(Date day) {
080: return getEndOfHour(day, Calendar.getInstance());
081: }
082:
083: public static Date getEndOfHour(Date day, Calendar cal) {
084: if (day == null || cal == null) {
085: return day;
086: }
087:
088: cal.setTime(day);
089: cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
090: cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
091: cal.set(Calendar.MILLISECOND, cal
092: .getMaximum(Calendar.MILLISECOND));
093: return cal.getTime();
094: }
095:
096: /**
097: * Returns a Date set to the first possible millisecond of the month, just
098: * after midnight. If a null day is passed in, a new Date is created.
099: * midnight (00m 00h 00s)
100: */
101: public static Date getStartOfMonth(Date day) {
102: return getStartOfMonth(day, Calendar.getInstance());
103: }
104:
105: public static Date getStartOfMonth(Date day, Calendar cal) {
106: if (day == null)
107: day = new Date();
108: cal.setTime(day);
109:
110: // set time to start of day
111: cal.set(Calendar.HOUR_OF_DAY, cal
112: .getMinimum(Calendar.HOUR_OF_DAY));
113: cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
114: cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
115: cal.set(Calendar.MILLISECOND, cal
116: .getMinimum(Calendar.MILLISECOND));
117:
118: // set time to first day of month
119: cal.set(Calendar.DAY_OF_MONTH, 1);
120:
121: return cal.getTime();
122: }
123:
124: /**
125: * Returns a Date set to the last possible millisecond of the month, just
126: * before midnight. If a null day is passed in, a new Date is created.
127: * midnight (00m 00h 00s)
128: */
129: public static Date getEndOfMonth(Date day) {
130: return getEndOfMonth(day, Calendar.getInstance());
131: }
132:
133: public static Date getEndOfMonth(Date day, Calendar cal) {
134: if (day == null)
135: day = new Date();
136: cal.setTime(day);
137:
138: // set time to end of day
139: cal.set(Calendar.HOUR_OF_DAY, cal
140: .getMaximum(Calendar.HOUR_OF_DAY));
141: cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
142: cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
143: cal.set(Calendar.MILLISECOND, cal
144: .getMaximum(Calendar.MILLISECOND));
145:
146: // set time to first day of month
147: cal.set(Calendar.DAY_OF_MONTH, 1);
148:
149: // add one month
150: cal.add(Calendar.MONTH, 1);
151:
152: // back up one day
153: cal.add(Calendar.DAY_OF_MONTH, -1);
154:
155: return cal.getTime();
156: }
157:
158: /**
159: * Returns a Date set to the first possible millisecond of the day, just
160: * after midnight. If a null day is passed in, a new Date is created.
161: * midnight (00m 00h 00s)
162: */
163: public static Date getStartOfDay(Date day) {
164: return getStartOfDay(day, Calendar.getInstance());
165: }
166:
167: /**
168: * Returns a Date set to the first possible millisecond of the day, just
169: * after midnight. If a null day is passed in, a new Date is created.
170: * midnight (00m 00h 00s)
171: */
172: public static Date getStartOfDay(Date day, Calendar cal) {
173: if (day == null)
174: day = new Date();
175: cal.setTime(day);
176: cal.set(Calendar.HOUR_OF_DAY, cal
177: .getMinimum(Calendar.HOUR_OF_DAY));
178: cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
179: cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
180: cal.set(Calendar.MILLISECOND, cal
181: .getMinimum(Calendar.MILLISECOND));
182: return cal.getTime();
183: }
184:
185: /**
186: * Returns a Date set just to Noon, to the closest possible millisecond
187: * of the day. If a null day is passed in, a new Date is created.
188: * nnoon (00m 12h 00s)
189: */
190: public static Date getNoonOfDay(Date day, Calendar cal) {
191: if (day == null)
192: day = new Date();
193: cal.setTime(day);
194: cal.set(Calendar.HOUR_OF_DAY, 12);
195: cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
196: cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
197: cal.set(Calendar.MILLISECOND, cal
198: .getMinimum(Calendar.MILLISECOND));
199: return cal.getTime();
200: }
201:
202: /**
203: * Returns a java.sql.Timestamp equal to the current time
204: **/
205: public static java.sql.Timestamp now() {
206: return new java.sql.Timestamp(new java.util.Date().getTime());
207: }
208:
209: /**
210: * Returns a string the represents the passed-in date parsed
211: * according to the passed-in format. Returns an empty string
212: * if the date or the format is null.
213: **/
214: public static String format(Date aDate, SimpleDateFormat aFormat) {
215: if (aDate == null || aFormat == null) {
216: return "";
217: }
218: synchronized (aFormat) {
219: return aFormat.format(aDate);
220: }
221: }
222:
223: /**
224: * Returns a Date using the passed-in string and format. Returns null if the string
225: * is null or empty or if the format is null. The string must match the format.
226: **/
227: public static Date parse(String aValue, SimpleDateFormat aFormat)
228: throws ParseException {
229: if (StringUtils.isEmpty(aValue) || aFormat == null) {
230: return null;
231: }
232: synchronized (aFormat) {
233: return aFormat.parse(aValue);
234: }
235: }
236:
237: /**
238: * Returns true if endDate is after startDate or if startDate equals endDate
239: * or if they are the same date. Returns false if either value is null.
240: **/
241: public static boolean isValidDateRange(Date startDate, Date endDate) {
242: return isValidDateRange(startDate, endDate, true);
243: }
244:
245: /**
246: * Returns true if endDate is after startDate or if startDate equals endDate.
247: * Returns false if either value is null. If equalOK, returns true if the
248: * dates are equal.
249: **/
250: public static boolean isValidDateRange(Date startDate,
251: Date endDate, boolean equalOK) {
252: // false if either value is null
253: if (startDate == null || endDate == null) {
254: return false;
255: }
256:
257: if (equalOK) {
258: // true if they are equal
259: if (startDate.equals(endDate)) {
260: return true;
261: }
262: }
263:
264: // true if endDate after startDate
265: if (endDate.after(startDate)) {
266: return true;
267: }
268:
269: return false;
270: }
271:
272: // convenience method returns minimal date format
273: public static SimpleDateFormat defaultDateFormat() {
274: return DateUtil.friendlyDateFormat(true);
275: }
276:
277: // convenience method returns minimal date format
278: public static java.text.SimpleDateFormat minimalDateFormat() {
279: return friendlyDateFormat(true);
280: }
281:
282: // convenience method that returns friendly data format
283: // using full month, day, year digits.
284: public static SimpleDateFormat fullDateFormat() {
285: return friendlyDateFormat(false);
286: }
287:
288: /**
289: * Returns a "friendly" date format.
290: * @param mimimalFormat Should the date format allow single digits.
291: **/
292: public static SimpleDateFormat friendlyDateFormat(
293: boolean minimalFormat) {
294: if (minimalFormat) {
295: return new SimpleDateFormat(formatDefaultDateMinimal);
296: }
297:
298: return new SimpleDateFormat(formatDefaultDate);
299: }
300:
301: // returns full timestamp format
302: public static SimpleDateFormat defaultTimestampFormat() {
303: return new SimpleDateFormat(formatDefaultTimestamp);
304: }
305:
306: // convenience method returns long friendly timestamp format
307: public static SimpleDateFormat friendlyTimestampFormat() {
308: return new SimpleDateFormat(formatFriendlyTimestamp);
309: }
310:
311: // convenience method returns minimal date format
312: public static SimpleDateFormat get8charDateFormat() {
313: return new SimpleDateFormat(format8chars);
314: }
315:
316: // convenience method returns minimal date format
317: public static SimpleDateFormat get6charDateFormat() {
318: return new SimpleDateFormat(format6chars);
319: }
320:
321: // convenience method returns minimal date format
322: public static SimpleDateFormat getIso8601DateFormat() {
323: return new SimpleDateFormat(formatIso8601);
324: }
325:
326: // convenience method returns minimal date format
327: public static SimpleDateFormat getIso8601DayDateFormat() {
328: return new SimpleDateFormat(formatIso8601Day);
329: }
330:
331: // convenience method returns minimal date format
332: public static SimpleDateFormat getRfc822DateFormat() {
333: // http://www.w3.org/Protocols/rfc822/Overview.html#z28
334: // Using Locale.US to fix ROL-725 and ROL-628
335: return new SimpleDateFormat(formatRfc822, Locale.US);
336: }
337:
338: // convenience method
339: public static String defaultDate(Date date) {
340: return format(date, defaultDateFormat());
341: }
342:
343: // convenience method using minimal date format
344: public static String minimalDate(Date date) {
345: return format(date, DateUtil.minimalDateFormat());
346: }
347:
348: public static String fullDate(Date date) {
349: return format(date, DateUtil.fullDateFormat());
350: }
351:
352: /**
353: * Format the date using the "friendly" date format.
354: */
355: public static String friendlyDate(Date date, boolean minimalFormat) {
356: return format(date, friendlyDateFormat(minimalFormat));
357: }
358:
359: // convenience method
360: public static String friendlyDate(Date date) {
361: return format(date, friendlyDateFormat(true));
362: }
363:
364: // convenience method
365: public static String defaultTimestamp(Date date) {
366: return format(date, defaultTimestampFormat());
367: }
368:
369: // convenience method returns long friendly formatted timestamp
370: public static String friendlyTimestamp(Date date) {
371: return format(date, friendlyTimestampFormat());
372: }
373:
374: // convenience method returns 8 char day stamp YYYYMMDD
375: public static String format8chars(Date date) {
376: return format(date, get8charDateFormat());
377: }
378:
379: // convenience method returns 6 char month stamp YYYYMM
380: public static String format6chars(Date date) {
381: return format(date, get6charDateFormat());
382: }
383:
384: // convenience method returns long friendly formatted timestamp
385: public static String formatIso8601Day(Date date) {
386: return format(date, getIso8601DayDateFormat());
387: }
388:
389: public static String formatRfc822(Date date) {
390: return format(date, getRfc822DateFormat());
391: }
392:
393: // This is a hack, but it seems to work
394: public static String formatIso8601(Date date) {
395: if (date == null)
396: return "";
397:
398: // Add a colon 2 chars before the end of the string
399: // to make it a valid ISO-8601 date.
400:
401: String str = format(date, getIso8601DateFormat());
402: StringBuffer sb = new StringBuffer();
403: sb.append(str.substring(0, str.length() - 2));
404: sb.append(":");
405: sb.append(str.substring(str.length() - 2));
406: return sb.toString();
407: }
408:
409: public static Date parseIso8601(String value) throws Exception {
410: return ISO8601DateParser.parse(value);
411: }
412:
413: /**
414: * Parse data as either 6-char or 8-char format.
415: */
416: public static Date parseWeblogURLDateString(String dateString,
417: TimeZone tz, Locale locale) {
418:
419: Date ret = new Date();
420: SimpleDateFormat char8DateFormat = DateUtil
421: .get8charDateFormat();
422: SimpleDateFormat char6DateFormat = DateUtil
423: .get6charDateFormat();
424:
425: if (dateString != null && dateString.length() == 8
426: && StringUtils.isNumeric(dateString)) {
427: ParsePosition pos = new ParsePosition(0);
428: ret = char8DateFormat.parse(dateString, pos);
429:
430: // make sure the requested date is not in the future
431: Date today = null;
432: Calendar todayCal = Calendar.getInstance();
433: todayCal = Calendar.getInstance(tz, locale);
434: todayCal.setTime(new Date());
435: today = todayCal.getTime();
436: if (ret.after(today)) {
437: ret = today;
438: }
439:
440: } else if (dateString != null && dateString.length() == 6
441: && StringUtils.isNumeric(dateString)) {
442: ParsePosition pos = new ParsePosition(0);
443: ret = char6DateFormat.parse(dateString, pos);
444:
445: // make sure the requested date is not in the future
446: Calendar todayCal = Calendar.getInstance();
447: todayCal = Calendar.getInstance(tz, locale);
448: todayCal.setTime(new Date());
449: Date today = todayCal.getTime();
450: if (ret.after(today)) {
451: ret = today;
452: }
453: }
454:
455: return ret;
456: }
457:
458: }
|