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 */ 017package org.apache.commons.validator.routines; 018 019import java.text.DateFormat; 020import java.text.Format; 021import java.util.Calendar; 022import java.util.Date; 023import java.util.Locale; 024import 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 successfully 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, returning 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, returning 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, returning 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, returning 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, returning 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$ 083 * @since Validator 1.3.0 084 */ 085public class DateValidator extends AbstractCalendarValidator { 086 087 private static final long serialVersionUID = -3966328400469953190L; 088 089 private static final DateValidator VALIDATOR = new DateValidator(); 090 091 /** 092 * Return a singleton instance of this validator. 093 * @return A singleton instance of the DateValidator. 094 */ 095 public static DateValidator getInstance() { 096 return VALIDATOR; 097 } 098 099 /** 100 * Construct a <i>strict</i> instance with <i>short</i> 101 * date style. 102 */ 103 public DateValidator() { 104 this(true, DateFormat.SHORT); 105 } 106 107 /** 108 * Construct an instance with the specified <i>strict</i> 109 * and <i>date style</i> parameters. 110 * 111 * @param strict <code>true</code> if strict 112 * <code>Format</code> parsing should be used. 113 * @param dateStyle the date style to use for Locale validation. 114 */ 115 public DateValidator(boolean strict, int dateStyle) { 116 super(strict, dateStyle, -1); 117 } 118 119 /** 120 * <p>Validate/convert a <code>Date</code> using the default 121 * <code>Locale</code> and <code>TimeZone</code>. 122 * 123 * @param value The value validation is being performed on. 124 * @return The parsed <code>Date</code> if valid or <code>null</code> 125 * if invalid. 126 */ 127 public Date validate(String value) { 128 return (Date)parse(value, (String)null, (Locale)null, (TimeZone)null); 129 } 130 131 /** 132 * <p>Validate/convert a <code>Date</code> using the specified 133 * <code>TimeZone</code> and default <code>Locale</code>. 134 * 135 * @param value The value validation is being performed on. 136 * @param timeZone The Time Zone used to parse the date, system default if null. 137 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid. 138 */ 139 public Date validate(String value, TimeZone timeZone) { 140 return (Date)parse(value, (String)null, (Locale)null, timeZone); 141 } 142 143 /** 144 * <p>Validate/convert a <code>Date</code> using the specified 145 * <i>pattern</i> and default <code>TimeZone</code>. 146 * 147 * @param value The value validation is being performed on. 148 * @param pattern The pattern used to validate the value against, or the 149 * default for the <code>Locale</code> if <code>null</code>. 150 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid. 151 */ 152 public Date validate(String value, String pattern) { 153 return (Date)parse(value, pattern, (Locale)null, (TimeZone)null); 154 } 155 156 /** 157 * <p>Validate/convert a <code>Date</code> using the specified 158 * <i>pattern</i> and <code>TimeZone</code>. 159 * 160 * @param value The value validation is being performed on. 161 * @param pattern The pattern used to validate the value against, or the 162 * default for the <code>Locale</code> if <code>null</code>. 163 * @param timeZone The Time Zone used to parse the date, system default if null. 164 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid. 165 */ 166 public Date validate(String value, String pattern, TimeZone timeZone) { 167 return (Date)parse(value, pattern, (Locale)null, timeZone); 168 } 169 170 /** 171 * <p>Validate/convert a <code>Date</code> using the specified 172 * <code>Locale</code> and default <code>TimeZone</code>. 173 * 174 * @param value The value validation is being performed on. 175 * @param locale The locale to use for the date format, system default if null. 176 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid. 177 */ 178 public Date validate(String value, Locale locale) { 179 return (Date)parse(value, (String)null, locale, (TimeZone)null); 180 } 181 182 /** 183 * <p>Validate/convert a <code>Date</code> using the specified 184 * <code>Locale</code> and <code>TimeZone</code>. 185 * 186 * @param value The value validation is being performed on. 187 * @param locale The locale to use for the date format, system default if null. 188 * @param timeZone The Time Zone used to parse the date, system default if null. 189 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid. 190 */ 191 public Date validate(String value, Locale locale, TimeZone timeZone) { 192 return (Date)parse(value, (String)null, locale, timeZone); 193 } 194 195 /** 196 * <p>Validate/convert a <code>Date</code> using the specified pattern 197 * and <code>Locale</code> and the default <code>TimeZone</code>. 198 * 199 * @param value The value validation is being performed on. 200 * @param pattern The pattern used to validate the value against, or the 201 * default for the <code>Locale</code> if <code>null</code>. 202 * @param locale The locale to use for the date format, system default if null. 203 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid. 204 */ 205 public Date validate(String value, String pattern, Locale locale) { 206 return (Date)parse(value, pattern, locale, (TimeZone)null); 207 } 208 209 /** 210 * <p>Validate/convert a <code>Date</code> using the specified 211 * pattern, and <code>Locale</code> and <code>TimeZone</code>. 212 * 213 * @param value The value validation is being performed on. 214 * @param pattern The pattern used to validate the value against, or the 215 * default for the <code>Locale</code> if <code>null</code>. 216 * @param locale The locale to use for the date format, system default if null. 217 * @param timeZone The Time Zone used to parse the date, system default if null. 218 * @return The parsed <code>Date</code> if valid or <code>null</code> if invalid. 219 */ 220 public Date validate(String value, String pattern, Locale locale, TimeZone timeZone) { 221 return (Date)parse(value, pattern, locale, timeZone); 222 } 223 224 /** 225 * <p>Compare Dates (day, month and year - not time).</p> 226 * 227 * @param value The <code>Calendar</code> value to check. 228 * @param compare The <code>Calendar</code> to compare the value to. 229 * @param timeZone The Time Zone used to compare the dates, system default if null. 230 * @return Zero if the dates are equal, -1 if first 231 * date is less than the seconds and +1 if the first 232 * date is greater than. 233 */ 234 public int compareDates(Date value, Date compare, TimeZone timeZone) { 235 Calendar calendarValue = getCalendar(value, timeZone); 236 Calendar calendarCompare = getCalendar(compare, timeZone); 237 return compare(calendarValue, calendarCompare, Calendar.DATE); 238 } 239 240 /** 241 * <p>Compare Weeks (week and year).</p> 242 * 243 * @param value The <code>Date</code> value to check. 244 * @param compare The <code>Date</code> to compare the value to. 245 * @param timeZone The Time Zone used to compare the dates, system default if null. 246 * @return Zero if the weeks are equal, -1 if first 247 * parameter's week is less than the seconds and +1 if the first 248 * parameter's week is greater than. 249 */ 250 public int compareWeeks(Date value, Date compare, TimeZone timeZone) { 251 Calendar calendarValue = getCalendar(value, timeZone); 252 Calendar calendarCompare = getCalendar(compare, timeZone); 253 return compare(calendarValue, calendarCompare, Calendar.WEEK_OF_YEAR); 254 } 255 256 /** 257 * <p>Compare Months (month and year).</p> 258 * 259 * @param value The <code>Date</code> value to check. 260 * @param compare The <code>Date</code> to compare the value to. 261 * @param timeZone The Time Zone used to compare the dates, system default if null. 262 * @return Zero if the months are equal, -1 if first 263 * parameter's month is less than the seconds and +1 if the first 264 * parameter's month is greater than. 265 */ 266 public int compareMonths(Date value, Date compare, TimeZone timeZone) { 267 Calendar calendarValue = getCalendar(value, timeZone); 268 Calendar calendarCompare = getCalendar(compare, timeZone); 269 return compare(calendarValue, calendarCompare, Calendar.MONTH); 270 } 271 272 /** 273 * <p>Compare Quarters (quarter and year).</p> 274 * 275 * @param value The <code>Date</code> value to check. 276 * @param compare The <code>Date</code> to compare the value to. 277 * @param timeZone The Time Zone used to compare the dates, system default if null. 278 * @return Zero if the months are equal, -1 if first 279 * parameter's quarter is less than the seconds and +1 if the first 280 * parameter's quarter is greater than. 281 */ 282 public int compareQuarters(Date value, Date compare, TimeZone timeZone) { 283 return compareQuarters(value, compare, timeZone, 1); 284 } 285 286 /** 287 * <p>Compare Quarters (quarter and year).</p> 288 * 289 * @param value The <code>Date</code> value to check. 290 * @param compare The <code>Date</code> to compare the value to. 291 * @param timeZone The Time Zone used to compare the dates, system default if null. 292 * @param monthOfFirstQuarter The month that the first quarter starts. 293 * @return Zero if the quarters are equal, -1 if first 294 * parameter's quarter is less than the seconds and +1 if the first 295 * parameter's quarter is greater than. 296 */ 297 public int compareQuarters(Date value, Date compare, TimeZone timeZone, int monthOfFirstQuarter) { 298 Calendar calendarValue = getCalendar(value, timeZone); 299 Calendar calendarCompare = getCalendar(compare, timeZone); 300 return super.compareQuarters(calendarValue, calendarCompare, monthOfFirstQuarter); 301 } 302 303 /** 304 * <p>Compare Years.</p> 305 * 306 * @param value The <code>Date</code> value to check. 307 * @param compare The <code>Date</code> to compare the value to. 308 * @param timeZone The Time Zone used to compare the dates, system default if null. 309 * @return Zero if the years are equal, -1 if first 310 * parameter's year is less than the seconds and +1 if the first 311 * parameter's year is greater than. 312 */ 313 public int compareYears(Date value, Date compare, TimeZone timeZone) { 314 Calendar calendarValue = getCalendar(value, timeZone); 315 Calendar calendarCompare = getCalendar(compare, timeZone); 316 return compare(calendarValue, calendarCompare, Calendar.YEAR); 317 } 318 319 /** 320 * <p>Returns the parsed <code>Date</code> unchanged.</p> 321 * 322 * @param value The parsed <code>Date</code> object created. 323 * @param formatter The Format used to parse the value with. 324 * @return The parsed value converted to a <code>Calendar</code>. 325 */ 326 @Override 327 protected Object processParsedValue(Object value, Format formatter) { 328 return value; 329 } 330 331 /** 332 * <p>Convert a <code>Date</code> to a <code>Calendar</code>.</p> 333 * 334 * @param value The date value to be converted. 335 * @return The converted <code>Calendar</code>. 336 */ 337 private Calendar getCalendar(Date value, TimeZone timeZone) { 338 339 Calendar calendar = null; 340 if (timeZone != null) { 341 calendar = Calendar.getInstance(timeZone); 342 } else { 343 calendar = Calendar.getInstance(); 344 } 345 calendar.setTime(value); 346 return calendar; 347 348 } 349 350}