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.validator.routines;
018
019 import java.text.DateFormat;
020 import java.text.Format;
021 import java.util.Calendar;
022 import java.util.Date;
023 import java.util.Locale;
024 import java.util.TimeZone;
025
026 /**
027 * <p><b>Date Validation</b> and Conversion routines (<code>java.util.Date</code>).</p>
028 *
029 * <p>This validator provides a number of methods for validating/converting
030 * a <code>String</code> date value to a <code>java.util.Date</code> using
031 * <code>java.text.DateFormat</code> to parse either:</p>
032 * <ul>
033 * <li>using the default format for the default <code>Locale</code></li>
034 * <li>using a specified pattern with the default <code>Locale</code></li>
035 * <li>using the default format for a specified <code>Locale</code></li>
036 * <li>using a specified pattern with a specified <code>Locale</code></li>
037 * </ul>
038 *
039 * <p>For each of the above mechanisms, conversion method (i.e the
040 * <code>validate</code> methods) implementations are provided which
041 * either use the default <code>TimeZone</code> or allow the
042 * <code>TimeZone</code> to be specified.</p>
043 *
044 * <p>Use one of the <code>isValid()</code> methods to just validate or
045 * one of the <code>validate()</code> methods to validate and receive a
046 * <i>converted</i> <code>Date</code> value.</p>
047 *
048 * <p>Implementations of the <code>validate()</code> method are provided
049 * to create <code>Date</code> objects for different <i>time zones</i>
050 * if the system default is not appropriate.</p>
051 *
052 * <p>Once a value has been sucessfully converted the following
053 * methods can be used to perform various date comparison checks:</p>
054 * <ul>
055 * <li><code>compareDates()</code> compares the day, month and
056 * year of two dates, returing 0, -1 or +1 indicating
057 * whether the first date is equal, before or after the second.</li>
058 * <li><code>compareWeeks()</code> compares the week and
059 * year of two dates, returing 0, -1 or +1 indicating
060 * whether the first week is equal, before or after the second.</li>
061 * <li><code>compareMonths()</code> compares the month and
062 * year of two dates, returing 0, -1 or +1 indicating
063 * whether the first month is equal, before or after the second.</li>
064 * <li><code>compareQuarters()</code> compares the quarter and
065 * year of two dates, returing 0, -1 or +1 indicating
066 * whether the first quarter is equal, before or after the second.</li>
067 * <li><code>compareYears()</code> compares the
068 * year of two dates, returing 0, -1 or +1 indicating
069 * whether the first year is equal, before or after the second.</li>
070 * </ul>
071 *
072 * <p>So that the same mechanism used for parsing an <i>input</i> value
073 * for validation can be used to format <i>output</i>, corresponding
074 * <code>format()</code> methods are also provided. That is you can
075 * format either:</p>
076 * <ul>
077 * <li>using a specified pattern</li>
078 * <li>using the format for a specified <code>Locale</code></li>
079 * <li>using the format for the <i>default</i> <code>Locale</code></li>
080 * </ul>
081 *
082 * @version $Revision: 493905 $ $Date: 2007-01-08 03:11:38 +0100 (Mo, 08. Jan 2007) $
083 * @since Validator 1.3.0
084 */
085 public class DateValidator extends AbstractCalendarValidator {
086
087 private static final DateValidator VALIDATOR = new DateValidator();
088
089 /**
090 * Return a singleton instance of this validator.
091 * @return A singleton instance of the DateValidator.
092 */
093 public static DateValidator getInstance() {
094 return VALIDATOR;
095 }
096
097 /**
098 * Construct a <i>strict</i> instance with <i>short</i>
099 * date style.
100 */
101 public DateValidator() {
102 this(true, DateFormat.SHORT);
103 }
104
105 /**
106 * Construct an instance with the specified <i>strict</i>
107 * and <i>date style</i> parameters.
108 *
109 * @param strict <code>true</code> if strict
110 * <code>Format</code> parsing should be used.
111 * @param dateStyle the date style to use for Locale validation.
112 */
113 public DateValidator(boolean strict, int dateStyle) {
114 super(strict, dateStyle, -1);
115 }
116
117 /**
118 * <p>Validate/convert a <code>Date</code> using the default
119 * <code>Locale</code> and <code>TimeZone</code>.
120 *
121 * @param value The value validation is being performed on.
122 * @return The parsed <code>Date</code> if valid or <code>null</code>
123 * if invalid.
124 */
125 public Date validate(String value) {
126 return (Date)parse(value, (String)null, (Locale)null, (TimeZone)null);
127 }
128
129 /**
130 * <p>Validate/convert a <code>Date</code> using the specified
131 * <code>TimeZone</code> and default <code>Locale</code>.
132 *
133 * @param value The value validation is being performed on.
134 * @param timeZone The Time Zone used to parse the date, system default if null.
135 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid.
136 */
137 public Date validate(String value, TimeZone timeZone) {
138 return (Date)parse(value, (String)null, (Locale)null, timeZone);
139 }
140
141 /**
142 * <p>Validate/convert a <code>Date</code> using the specified
143 * <i>pattern</i> and default <code>TimeZone</code>.
144 *
145 * @param value The value validation is being performed on.
146 * @param pattern The pattern used to validate the value against, or the
147 * default for the <code>Locale</code> if <code>null</code>.
148 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid.
149 */
150 public Date validate(String value, String pattern) {
151 return (Date)parse(value, pattern, (Locale)null, (TimeZone)null);
152 }
153
154 /**
155 * <p>Validate/convert a <code>Date</code> using the specified
156 * <i>pattern</i> and <code>TimeZone</code>.
157 *
158 * @param value The value validation is being performed on.
159 * @param pattern The pattern used to validate the value against, or the
160 * default for the <code>Locale</code> if <code>null</code>.
161 * @param timeZone The Time Zone used to parse the date, system default if null.
162 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid.
163 */
164 public Date validate(String value, String pattern, TimeZone timeZone) {
165 return (Date)parse(value, pattern, (Locale)null, timeZone);
166 }
167
168 /**
169 * <p>Validate/convert a <code>Date</code> using the specified
170 * <code>Locale</code> and default <code>TimeZone</code>.
171 *
172 * @param value The value validation is being performed on.
173 * @param locale The locale to use for the date format, system default if null.
174 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid.
175 */
176 public Date validate(String value, Locale locale) {
177 return (Date)parse(value, (String)null, locale, (TimeZone)null);
178 }
179
180 /**
181 * <p>Validate/convert a <code>Date</code> using the specified
182 * <code>Locale</code> and <code>TimeZone</code>.
183 *
184 * @param value The value validation is being performed on.
185 * @param locale The locale to use for the date format, system default if null.
186 * @param timeZone The Time Zone used to parse the date, system default if null.
187 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid.
188 */
189 public Date validate(String value, Locale locale, TimeZone timeZone) {
190 return (Date)parse(value, (String)null, locale, timeZone);
191 }
192
193 /**
194 * <p>Validate/convert a <code>Date</code> using the specified pattern
195 * and <code>Locale</code> and the default <code>TimeZone</code>.
196 *
197 * @param value The value validation is being performed on.
198 * @param pattern The pattern used to validate the value against, or the
199 * default for the <code>Locale</code> if <code>null</code>.
200 * @param locale The locale to use for the date format, system default if null.
201 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid.
202 */
203 public Date validate(String value, String pattern, Locale locale) {
204 return (Date)parse(value, pattern, locale, (TimeZone)null);
205 }
206
207 /**
208 * <p>Validate/convert a <code>Date</code> using the specified
209 * pattern, and <code>Locale</code> and <code>TimeZone</code>.
210 *
211 * @param value The value validation is being performed on.
212 * @param pattern The pattern used to validate the value against, or the
213 * default for the <code>Locale</code> if <code>null</code>.
214 * @param locale The locale to use for the date format, system default if null.
215 * @param timeZone The Time Zone used to parse the date, system default if null.
216 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid.
217 */
218 public Date validate(String value, String pattern, Locale locale, TimeZone timeZone) {
219 return (Date)parse(value, pattern, locale, timeZone);
220 }
221
222 /**
223 * <p>Compare Dates (day, month and year - not time).</p>
224 *
225 * @param value The <code>Calendar</code> value to check.
226 * @param compare The <code>Calendar</code> to compare the value to.
227 * @param timeZone The Time Zone used to compare the dates, system default if null.
228 * @return Zero if the dates are equal, -1 if first
229 * date is less than the seconds and +1 if the first
230 * date is greater than.
231 */
232 public int compareDates(Date value, Date compare, TimeZone timeZone) {
233 Calendar calendarValue = getCalendar(value, timeZone);
234 Calendar calendarCompare = getCalendar(compare, timeZone);
235 return compare(calendarValue, calendarCompare, Calendar.DATE);
236 }
237
238 /**
239 * <p>Compare Weeks (week and year).</p>
240 *
241 * @param value The <code>Date</code> value to check.
242 * @param compare The <code>Date</code> to compare the value to.
243 * @param timeZone The Time Zone used to compare the dates, system default if null.
244 * @return Zero if the weeks are equal, -1 if first
245 * parameter's week is less than the seconds and +1 if the first
246 * parameter's week is greater than.
247 */
248 public int compareWeeks(Date value, Date compare, TimeZone timeZone) {
249 Calendar calendarValue = getCalendar(value, timeZone);
250 Calendar calendarCompare = getCalendar(compare, timeZone);
251 return compare(calendarValue, calendarCompare, Calendar.WEEK_OF_YEAR);
252 }
253
254 /**
255 * <p>Compare Months (month and year).</p>
256 *
257 * @param value The <code>Date</code> value to check.
258 * @param compare The <code>Date</code> to compare the value to.
259 * @param timeZone The Time Zone used to compare the dates, system default if null.
260 * @return Zero if the months are equal, -1 if first
261 * parameter's month is less than the seconds and +1 if the first
262 * parameter's month is greater than.
263 */
264 public int compareMonths(Date value, Date compare, TimeZone timeZone) {
265 Calendar calendarValue = getCalendar(value, timeZone);
266 Calendar calendarCompare = getCalendar(compare, timeZone);
267 return compare(calendarValue, calendarCompare, Calendar.MONTH);
268 }
269
270 /**
271 * <p>Compare Quarters (quarter and year).</p>
272 *
273 * @param value The <code>Date</code> value to check.
274 * @param compare The <code>Date</code> to compare the value to.
275 * @param timeZone The Time Zone used to compare the dates, system default if null.
276 * @return Zero if the months are equal, -1 if first
277 * parameter's quarter is less than the seconds and +1 if the first
278 * parameter's quarter is greater than.
279 */
280 public int compareQuarters(Date value, Date compare, TimeZone timeZone) {
281 return compareQuarters(value, compare, timeZone, 1);
282 }
283
284 /**
285 * <p>Compare Quarters (quarter and year).</p>
286 *
287 * @param value The <code>Date</code> value to check.
288 * @param compare The <code>Date</code> to compare the value to.
289 * @param timeZone The Time Zone used to compare the dates, system default if null.
290 * @param monthOfFirstQuarter The month that the first quarter starts.
291 * @return Zero if the quarters are equal, -1 if first
292 * parameter's quarter is less than the seconds and +1 if the first
293 * parameter's quarter is greater than.
294 */
295 public int compareQuarters(Date value, Date compare, TimeZone timeZone, int monthOfFirstQuarter) {
296 Calendar calendarValue = getCalendar(value, timeZone);
297 Calendar calendarCompare = getCalendar(compare, timeZone);
298 return super.compareQuarters(calendarValue, calendarCompare, monthOfFirstQuarter);
299 }
300
301 /**
302 * <p>Compare Years.</p>
303 *
304 * @param value The <code>Date</code> value to check.
305 * @param compare The <code>Date</code> to compare the value to.
306 * @param timeZone The Time Zone used to compare the dates, system default if null.
307 * @return Zero if the years are equal, -1 if first
308 * parameter's year is less than the seconds and +1 if the first
309 * parameter's year is greater than.
310 */
311 public int compareYears(Date value, Date compare, TimeZone timeZone) {
312 Calendar calendarValue = getCalendar(value, timeZone);
313 Calendar calendarCompare = getCalendar(compare, timeZone);
314 return compare(calendarValue, calendarCompare, Calendar.YEAR);
315 }
316
317 /**
318 * <p>Returns the parsed <code>Date</code> unchanged.</p>
319 *
320 * @param value The parsed <code>Date</code> object created.
321 * @param formatter The Format used to parse the value with.
322 * @return The parsed value converted to a <code>Calendar</code>.
323 */
324 protected Object processParsedValue(Object value, Format formatter) {
325 return value;
326 }
327
328 /**
329 * <p>Convert a <code>Date</code> to a <code>Calendar</code>.</p>
330 *
331 * @param value The date value to be converted.
332 * @return The converted <code>Calendar</code>.
333 */
334 private Calendar getCalendar(Date value, TimeZone timeZone) {
335
336 Calendar calendar = null;
337 if (timeZone != null) {
338 calendar = Calendar.getInstance(timeZone);
339 } else {
340 calendar = Calendar.getInstance();
341 }
342 calendar.setTime(value);
343 return calendar;
344
345 }
346
347 }