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 *      https://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;
018
019import java.text.DateFormat;
020import java.text.ParseException;
021import java.text.ParsePosition;
022import java.text.SimpleDateFormat;
023import java.util.Locale;
024
025/**
026 * Perform date validations.
027 * <p>
028 * This class is a Singleton; you can retrieve the instance via the
029 * getInstance() method.
030 * </p>
031 *
032 * @since 1.1
033 * @deprecated Use the new DateValidator, CalendarValidator or TimeValidator in the
034 * routines package. This class will be removed in a future release.
035 */
036@Deprecated
037public class DateValidator {
038
039    /**
040     * Singleton instance of this class.
041     */
042    private static final DateValidator DATE_VALIDATOR = new DateValidator();
043
044    /**
045     * Returns the Singleton instance of this validator.
046     *
047     * @return A singleton instance of the DateValidator.
048     */
049    public static DateValidator getInstance() {
050        return DATE_VALIDATOR;
051    }
052
053    /**
054     * Protected constructor for subclasses to use.
055     */
056    protected DateValidator() {
057    }
058
059    /**
060     * Checks if the field is a valid date. The {@link Locale} is
061     * used with {@link DateFormat}. The setLenient method
062     * is set to {@code false} for all.
063     *
064     * @param value The value validation is being performed on.
065     * @param locale The locale to use for the date format, defaults to the default
066     * system default if null.
067     * @return true if the date is valid.
068     */
069    public boolean isValid(final String value, final Locale locale) {
070        if (value == null) {
071            return false;
072        }
073        final DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Validator.toLocale(locale));
074        formatter.setLenient(false);
075        try {
076            formatter.parse(value);
077        } catch (final ParseException e) {
078            return false;
079        }
080        return true;
081    }
082
083    /**
084     * Checks if the field is a valid date.  The pattern is used with
085     * {@link SimpleDateFormat}. If strict is true, then the
086     * length will be checked so '2/12/1999' will not pass validation with
087     * the format 'MM/dd/yyyy' because the month isn't two digits.
088     * The setLenient method is set to {@code false} for all.
089     *
090     * @param value The value validation is being performed on.
091     * @param datePattern The pattern passed to {@link SimpleDateFormat}.
092     * @param strict Whether or not to have an exact match of the datePattern.
093     * @return true if the date is valid.
094     */
095    public boolean isValid(final String value, final String datePattern, final boolean strict) {
096        if (value == null || datePattern == null || datePattern.isEmpty()) {
097            return false;
098        }
099        final SimpleDateFormat formatter = new SimpleDateFormat(datePattern);
100        formatter.setLenient(false);
101        final ParsePosition pos = new ParsePosition(0);
102        // parse(String, ParsePosition) stops at the first unparsable character instead of failing, so a strict
103        // match must also confirm the whole value was consumed; otherwise trailing text such as the 'f' in
104        // "11/11/199f" is dropped and the truncated date validates.
105        if (formatter.parse(value, pos) == null || strict && (pos.getIndex() < value.length() || datePattern.length() != value.length())) {
106            return false;
107        }
108        return true;
109    }
110
111}