1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.validator.routines;
18
19 import java.text.DateFormat;
20 import java.text.Format;
21 import java.util.Calendar;
22 import java.util.Locale;
23 import java.util.TimeZone;
24
25 /**
26 * <p><strong>Calendar Validation</strong> and Conversion routines ({@code java.util.Calendar}).</p>
27 *
28 * <p>This validator provides a number of methods for validating/converting
29 * a {@link String} date value to a {@code java.util.Calendar} using
30 * {@link DateFormat} to parse either:</p>
31 * <ul>
32 * <li>using the default format for the default {@link Locale}</li>
33 * <li>using a specified pattern with the default {@link Locale}</li>
34 * <li>using the default format for a specified {@link Locale}</li>
35 * <li>using a specified pattern with a specified {@link Locale}</li>
36 * </ul>
37 *
38 * <p>For each of the above mechanisms, conversion method (that is, the
39 * {@code validate} methods) implementations are provided which
40 * either use the default {@code TimeZone} or allow the
41 * {@code TimeZone} to be specified.</p>
42 *
43 * <p>Use one of the {@code isValid()} methods to just validate or
44 * one of the {@code validate()} methods to validate and receive a
45 * <em>converted</em> {@link Calendar} value.</p>
46 *
47 * <p>Implementations of the {@code validate()} method are provided
48 * to create {@link Calendar} objects for different <em>time zones</em>
49 * if the system default is not appropriate.</p>
50 *
51 * <p>Alternatively the CalendarValidator's {@code adjustToTimeZone()} method
52 * can be used to adjust the {@code TimeZone} of the {@link Calendar}
53 * object afterward.</p>
54 *
55 * <p>Once a value has been successfully converted the following
56 * methods can be used to perform various date comparison checks:</p>
57 * <ul>
58 * <li>{@code compareDates()} compares the day, month and
59 * year of two calendars, returning 0, -1 or +1 indicating
60 * whether the first date is equal, before or after the second.</li>
61 * <li>{@code compareWeeks()} compares the week and
62 * year of two calendars, returning 0, -1 or +1 indicating
63 * whether the first week is equal, before or after the second.</li>
64 * <li>{@code compareMonths()} compares the month and
65 * year of two calendars, returning 0, -1 or +1 indicating
66 * whether the first month is equal, before or after the second.</li>
67 * <li>{@code compareQuarters()} compares the quarter and
68 * year of two calendars, returning 0, -1 or +1 indicating
69 * whether the first quarter is equal, before or after the second.</li>
70 * <li>{@code compareYears()} compares the
71 * year of two calendars, returning 0, -1 or +1 indicating
72 * whether the first year is equal, before or after the second.</li>
73 * </ul>
74 *
75 * <p>So that the same mechanism used for parsing an <em>input</em> value
76 * for validation can be used to format <em>output</em>, corresponding
77 * {@code format()} methods are also provided. That is you can
78 * format either:</p>
79 * <ul>
80 * <li>using a specified pattern</li>
81 * <li>using the format for a specified {@link Locale}</li>
82 * <li>using the format for the <em>default</em> {@link Locale}</li>
83 * </ul>
84 *
85 * @since 1.3.0
86 */
87 public class CalendarValidator extends AbstractCalendarValidator {
88
89 private static final long serialVersionUID = 9109652318762134167L;
90
91 private static final CalendarValidator VALIDATOR = new CalendarValidator();
92
93 /**
94 * <p>Adjusts a Calendar's value to a different TimeZone.</p>
95 *
96 * @param value The value to adjust.
97 * @param timeZone The new time zone to use to adjust the Calendar to.
98 */
99 public static void adjustToTimeZone(final Calendar value, final TimeZone timeZone) {
100 if (value.getTimeZone().hasSameRules(timeZone)) {
101 value.setTimeZone(timeZone);
102 } else {
103 final int year = value.get(Calendar.YEAR);
104 final int month = value.get(Calendar.MONTH);
105 final int date = value.get(Calendar.DATE);
106 final int hour = value.get(Calendar.HOUR_OF_DAY);
107 final int minute = value.get(Calendar.MINUTE);
108 value.setTimeZone(timeZone);
109 value.set(year, month, date, hour, minute);
110 }
111 }
112
113 /**
114 * Gets the singleton instance of this validator.
115 *
116 * @return A singleton instance of the CalendarValidator.
117 */
118 public static CalendarValidator getInstance() {
119 return VALIDATOR;
120 }
121
122 /**
123 * Constructs a <em>strict</em> instance with <em>short</em>
124 * date style.
125 */
126 public CalendarValidator() {
127 this(true, DateFormat.SHORT);
128 }
129
130 /**
131 * Constructs an instance with the specified <em>strict</em>
132 * and <em>date style</em> parameters.
133 *
134 * @param strict {@code true} if strict
135 * {@code Format} parsing should be used.
136 * @param dateStyle the date style to use for Locale validation.
137 */
138 public CalendarValidator(final boolean strict, final int dateStyle) {
139 super(strict, dateStyle, -1);
140 }
141
142 /**
143 * <p>Compare Dates (day, month and year - not time).</p>
144 *
145 * @param value The {@link Calendar} value to check.
146 * @param compare The {@link Calendar} to compare the value to.
147 * @return Zero if the dates are equal, -1 if first
148 * date is less than the seconds and +1 if the first
149 * date is greater than.
150 */
151 public int compareDates(final Calendar value, final Calendar compare) {
152 return compare(value, compare, Calendar.DATE);
153 }
154
155 /**
156 * <p>Compare Months (month and year).</p>
157 *
158 * @param value The {@link Calendar} value to check.
159 * @param compare The {@link Calendar} to compare the value to.
160 * @return Zero if the months are equal, -1 if first
161 * parameter's month is less than the seconds and +1 if the first
162 * parameter's month is greater than.
163 */
164 public int compareMonths(final Calendar value, final Calendar compare) {
165 return compare(value, compare, Calendar.MONTH);
166 }
167
168 /**
169 * <p>Compare Quarters (quarter and year).</p>
170 *
171 * @param value The {@link Calendar} value to check.
172 * @param compare The {@link Calendar} to check the value against.
173 * @return Zero if the quarters are equal, -1 if first
174 * parameter's quarter is less than the seconds and +1 if the first
175 * parameter's quarter is greater than.
176 */
177 public int compareQuarters(final Calendar value, final Calendar compare) {
178 return compareQuarters(value, compare, 1);
179 }
180
181 /**
182 * <p>Compare Quarters (quarter and year).</p>
183 *
184 * @param value The {@link Calendar} value to check.
185 * @param compare The {@link Calendar} to compare the value to.
186 * @param monthOfFirstQuarter The month that the first quarter starts.
187 * @return Zero if the quarters are equal, -1 if first
188 * parameter's quarter is less than the seconds and +1 if the first
189 * parameter's quarter is greater than.
190 */
191 @Override
192 public int compareQuarters(final Calendar value, final Calendar compare, final int monthOfFirstQuarter) {
193 return super.compareQuarters(value, compare, monthOfFirstQuarter);
194 }
195
196 /**
197 * <p>Compare Weeks (week and year).</p>
198 *
199 * @param value The {@link Calendar} value to check.
200 * @param compare The {@link Calendar} to compare the value to.
201 * @return Zero if the weeks are equal, -1 if first
202 * parameter's week is less than the seconds and +1 if the first
203 * parameter's week is greater than.
204 */
205 public int compareWeeks(final Calendar value, final Calendar compare) {
206 return compare(value, compare, Calendar.WEEK_OF_YEAR);
207 }
208
209 /**
210 * <p>Compare Years.</p>
211 *
212 * @param value The {@link Calendar} value to check.
213 * @param compare The {@link Calendar} to compare the value to.
214 * @return Zero if the years are equal, -1 if first
215 * parameter's year is less than the seconds and +1 if the first
216 * parameter's year is greater than.
217 */
218 public int compareYears(final Calendar value, final Calendar compare) {
219 return compare(value, compare, Calendar.YEAR);
220 }
221
222 /**
223 * <p>Convert the parsed {@code Date} to a {@link Calendar}.</p>
224 *
225 * @param value The parsed {@code Date} object created.
226 * @param formatter The Format used to parse the value with.
227 * @return The parsed value converted to a {@link Calendar}.
228 */
229 @Override
230 protected Object processParsedValue(final Object value, final Format formatter) {
231 return ((DateFormat) formatter).getCalendar();
232 }
233
234 /**
235 * <p>Validate/convert a {@link Calendar} using the default
236 * {@link Locale} and {@code TimeZone}.
237 *
238 * @param value The value validation is being performed on.
239 * @return The parsed {@link Calendar} if valid or {@code null}
240 * if invalid.
241 */
242 public Calendar validate(final String value) {
243 return (Calendar) parse(value, (String) null, (Locale) null, (TimeZone) null);
244 }
245
246 /**
247 * <p>Validate/convert a {@link Calendar} using the specified
248 * {@link Locale} and default {@code TimeZone}.
249 *
250 * @param value The value validation is being performed on.
251 * @param locale The locale to use for the date format, system default if null.
252 * @return The parsed {@link Calendar} if valid or {@code null} if invalid.
253 */
254 public Calendar validate(final String value, final Locale locale) {
255 return (Calendar) parse(value, (String) null, locale, (TimeZone) null);
256 }
257
258 /**
259 * <p>Validate/convert a {@link Calendar} using the specified
260 * {@link Locale} and {@code TimeZone}.
261 *
262 * @param value The value validation is being performed on.
263 * @param locale The locale to use for the date format, system default if null.
264 * @param timeZone The Time Zone used to parse the date, system default if null.
265 * @return The parsed {@link Calendar} if valid or {@code null} if invalid.
266 */
267 public Calendar validate(final String value, final Locale locale, final TimeZone timeZone) {
268 return (Calendar) parse(value, (String) null, locale, timeZone);
269 }
270
271 /**
272 * <p>Validate/convert a {@link Calendar} using the specified
273 * <em>pattern</em> and default {@code TimeZone}.
274 *
275 * @param value The value validation is being performed on.
276 * @param pattern The pattern used to validate the value against.
277 * @return The parsed {@link Calendar} if valid or {@code null} if invalid.
278 */
279 public Calendar validate(final String value, final String pattern) {
280 return (Calendar) parse(value, pattern, (Locale) null, (TimeZone) null);
281 }
282
283 /**
284 * <p>Validate/convert a {@link Calendar} using the specified pattern
285 * and {@link Locale} and the default {@code TimeZone}.
286 *
287 * @param value The value validation is being performed on.
288 * @param pattern The pattern used to validate the value against, or the
289 * default for the {@link Locale} if {@code null}.
290 * @param locale The locale to use for the date format, system default if null.
291 * @return The parsed {@link Calendar} if valid or {@code null} if invalid.
292 */
293 public Calendar validate(final String value, final String pattern, final Locale locale) {
294 return (Calendar) parse(value, pattern, locale, (TimeZone) null);
295 }
296
297 /**
298 * <p>Validate/convert a {@link Calendar} using the specified
299 * pattern, and {@link Locale} and {@code TimeZone}.
300 *
301 * @param value The value validation is being performed on.
302 * @param pattern The pattern used to validate the value against, or the
303 * default for the {@link Locale} if {@code null}.
304 * @param locale The locale to use for the date format, system default if null.
305 * @param timeZone The Time Zone used to parse the date, system default if null.
306 * @return The parsed {@link Calendar} if valid or {@code null} if invalid.
307 */
308 public Calendar validate(final String value, final String pattern, final Locale locale, final TimeZone timeZone) {
309 return (Calendar) parse(value, pattern, locale, timeZone);
310 }
311
312 /**
313 * <p>Validate/convert a {@link Calendar} using the specified
314 * <em>pattern</em> and {@code TimeZone}.
315 *
316 * @param value The value validation is being performed on.
317 * @param pattern The pattern used to validate the value against.
318 * @param timeZone The Time Zone used to parse the date, system default if null.
319 * @return The parsed {@link Calendar} if valid or {@code null} if invalid.
320 */
321 public Calendar validate(final String value, final String pattern, final TimeZone timeZone) {
322 return (Calendar) parse(value, pattern, (Locale) null, timeZone);
323 }
324
325 /**
326 * <p>Validate/convert a {@link Calendar} using the specified
327 * {@code TimeZone} and default {@link Locale}.
328 *
329 * @param value The value validation is being performed on.
330 * @param timeZone The Time Zone used to parse the date, system default if null.
331 * @return The parsed {@link Calendar} if valid or {@code null}
332 * if invalid.
333 */
334 public Calendar validate(final String value, final TimeZone timeZone) {
335 return (Calendar) parse(value, (String) null, (Locale) null, timeZone);
336 }
337
338 }