Как проверить работоспособность даты в Java

Мне кажется любопытным, что наиболее очевидный способ создания объектов Date в Java устарел и, похоже, был «заменен» не столь очевидным для использования мягким календарем.

Как вы проверяете, что дата, заданная как комбинация дня, месяца и года, является действительной датой?

Например, 31 февраля 2008 г. (как в формате гггг-мм-дд) будет недопустимой датой.

Если у вас возникнет подобный вопрос, подумайте, нужна ли вам поддержка не григорианского календаря.

MSalters 12.04.2010 18:31

@JasonC Я полностью согласен с вами, их объединение выглядит лучшим способом.

acm 23.09.2016 09:05
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
87
2
219 741
21
Перейти к ответу Данный вопрос помечен как решенный

Ответы 21

Ответ принят как подходящий

Текущий способ - использовать класс календаря. У него есть метод setLenient, который будет проверять дату и генерировать исключение, если он выходит за пределы диапазона, как в вашем примере.

Забыл добавить: Если вы получаете экземпляр календаря и устанавливаете время, используя вашу дату, это то, как вы получаете проверку.

Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.setTime(yourDate);
try {
    cal.getTime();
}
catch (Exception e) {
  System.out.println("Invalid date");
}

не думаю, что это работает как есть. Calendar.setTime принимает java.util.Date, поэтому преобразование из строки уже произошло к тому моменту, когда вы получите объект yourDate.

tardate 21.05.2009 14:08

3 проблемы с примером кода: 1. После получения экземпляра Calendar вы должны вызвать cal.setLenient (false). В противном случае дата, подобная 31 февраля 2007 г., будет считаться действительной. 2. Cal.setTime () не генерирует исключение. Вы должны вызвать cal.getTime () после вызова setTime (), который вызывает исключение в недопустимую дату. 3. Опечатка: отсутствует символ "}" перед уловкой.

Liron Yahdav 25.04.2010 05:14

Это также медленнее, чем другие подходы. См. stackoverflow.com/questions/2149680/…

despot 15.08.2013 15:59

К вашему сведению, неприятные старые классы даты и времени, такие как java.util.Date, java.util.Calendar и java.text.SimpleDateFormat, теперь являются наследие, вытесненными классами java.time, встроенными в Java 8 и новее. См. Руководство от Oracle.

Basil Bourque 08.04.2018 02:50

не проверяет такие даты, как 31 февраля

shikha singh 29.07.2019 13:37

Вы можете использовать SimpleDateFormat

Например что-то вроде:

boolean isLegalDate(String s) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    sdf.setLenient(false);
    return sdf.parse(s, new ParsePosition(0)) != null;
}

Одна из проблем с этим подходом заключается в том, что он будет принимать 0003-0002-001.

despot 15.08.2013 13:15

Другая проблема заключается в том, что установка 13 в месяце возвращает дату, в которой месяц равен 01 в следующем году.

8bitjunkie 13.12.2013 17:34

К вашему сведению, ужасно неприятные старые классы даты и времени, такие как java.util.Date, java.util.Calendar и java.text.SimpleDateFormat, теперь являются наследие, вытесненными классами java.time, встроенными в Java 8 и новее. См. Руководство от Oracle.

Basil Bourque 11.08.2018 21:37

Как показывает @Maglob, основной подход состоит в том, чтобы протестировать преобразование строки в дату с помощью SimpleDateFormat.parse. Это будет ловить недопустимые комбинации дня / месяца, например, 2008-02-31.

Однако на практике этого бывает достаточно редко, поскольку SimpleDateFormat.parse чрезвычайно либерален. Есть два варианта поведения, которые могут вас заинтересовать:

Недействительные символы в строке даты Удивительно, но 2008-02-2x будет "проходить" как допустимую дату с locale format = "yyyy-MM-dd", например. Даже когда isLenient == false.

Годы: 2, 3 или 4 цифры? Вы также можете использовать 4-значные годы вместо того, чтобы разрешать поведение SimpleDateFormat по умолчанию (которое будет интерпретировать «12-02-31» по-разному в зависимости от того, был ли ваш формат «гггг-ММ-дд» или «гг-ММ-дд». )

Строгое решение со стандартной библиотекой

Таким образом, полная проверка строки на дату может выглядеть так: комбинация совпадения регулярного выражения и последующего принудительного преобразования даты. Хитрость с регулярным выражением заключается в том, чтобы сделать его адаптированным к локали.

  Date parseDate(String maybeDate, String format, boolean lenient) {
    Date date = null;

    // test date string matches format structure using regex
    // - weed out illegal characters and enforce 4-digit year
    // - create the regex based on the local format string
    String reFormat = Pattern.compile("d+|M+").matcher(Matcher.quoteReplacement(format)).replaceAll("\\\\d{1,2}");
    reFormat = Pattern.compile("y+").matcher(reFormat).replaceAll("\\\\d{4}");
    if ( Pattern.compile(reFormat).matcher(maybeDate).matches() ) {

      // date string matches format structure, 
      // - now test it can be converted to a valid date
      SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance();
      sdf.applyPattern(format);
      sdf.setLenient(lenient);
      try { date = sdf.parse(maybeDate); } catch (ParseException e) { }
    } 
    return date;
  } 

  // used like this:
  Date date = parseDate( "21/5/2009", "d/M/yyyy", false);

Обратите внимание, что регулярное выражение предполагает, что строка формата содержит только символы дня, месяца, года и разделителя. Кроме того, формат может быть в любом формате локали: «д / ММ / гг», «гггг-ММ-дд» и так далее. Строку формата для текущей локали можно получить следующим образом:

Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );
String format = sdf.toPattern();

Джода Тайм - лучшая альтернатива?

Я недавно слышал о время йода и подумал, что сравню. Два момента:

  1. Кажется, лучше строго относиться к недопустимым символам в строке даты, в отличие от SimpleDateFormat
  2. Пока не вижу способа ввести с ним 4-значные годы (но я думаю, вы могли бы создать свой собственный DateTimeFormatter для этой цели)

Использовать довольно просто:

import org.joda.time.format.*;
import org.joda.time.DateTime;

org.joda.time.DateTime parseDate(String maybeDate, String format) {
  org.joda.time.DateTime date = null;
  try {
    DateTimeFormatter fmt = DateTimeFormat.forPattern(format);
    date =  fmt.parseDateTime(maybeDate);
  } catch (Exception e) { }
  return date;
}

Я закончил с альтернативой joda и сам проверил, что значение соответствует длине шаблона ...

Xtreme Biker 04.08.2016 18:43

Обновление: ужасные старые устаревшие классы (Date, SimpleDateFormat и т. д.) Теперь заменены современными классами java.time. Точно так же проект Джода-Тайм находится в режиме обслуживания и рекомендует переход на классы java.time.

Basil Bourque 11.08.2018 21:31

Два комментария по использованию SimpleDateFormat.

it should be declared as a static instance if declared as static access should be synchronized as it is not thread safe

TIME, что лучше, чем создание экземпляра для каждого синтаксического анализа даты.

хорошее замечание Том. Я обновил приведенный мной пример, чтобы постоянно использовать статический экземпляр.

tardate 22.05.2009 08:04

Использование синхронизированной функции может не масштабироваться для некоторых проектов. Я бы рекомендовал поместить SimpleDateFormat в переменную ThreadLocal вместо статической переменной, доступ к которой осуществляется через синхронизированную функцию.

user327961 08.05.2014 23:50

Альтернативное строгое решение с использованием стандартной библиотеки - выполнить следующее:

1) Создайте строгий SimpleDateFormat, используя свой шаблон

2) Попытка проанализировать введенное пользователем значение с помощью объекта формата

3) В случае успеха переформатируйте дату, полученную из (2), используя тот же формат даты (из (1)).

4) Сравните переформатированную дату с исходным значением, введенным пользователем. Если они равны, то введенное значение строго соответствует вашему шаблону.

Таким образом, вам не нужно создавать сложные регулярные выражения - в моем случае мне нужно было поддерживать весь синтаксис шаблона SimpleDateFormat, а не ограничиваться определенными типами, такими как дни, месяцы и годы.

Это определенно правильный путь, см. Также пример кода на dreamincode.net/forums/topic/…

Victor Ionescu 13.06.2012 17:30

Предполагая, что оба они являются строками (иначе они уже были бы действительными датами), вот один способ:

package cruft;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateValidator
{
    private static final DateFormat DEFAULT_FORMATTER;

    static
    {
        DEFAULT_FORMATTER = new SimpleDateFormat("dd-MM-yyyy");
        DEFAULT_FORMATTER.setLenient(false);
    }

    public static void main(String[] args)
    {
        for (String dateString : args)
        {
            try
            {
                System.out.println("arg: " + dateString + " date: " + convertDateString(dateString));
            }
            catch (ParseException e)
            {
                System.out.println("could not parse " + dateString);
            }
        }
    }

    public static Date convertDateString(String dateString) throws ParseException
    {
        return DEFAULT_FORMATTER.parse(dateString);
    }
}

Вот результат, который я получаю:

java cruft.DateValidator 32-11-2010 31-02-2010 04-01-2011
could not parse 32-11-2010
could not parse 31-02-2010
arg: 04-01-2011 date: Tue Jan 04 00:00:00 EST 2011

Process finished with exit code 0

Как видите, он отлично справляется с обоими вашими случаями.

@duffymo второй оператор не генерирует исключение ... :(

maximus 24.12.2010 22:52

@Pangea Не совсем .... попробуйте эту дату "31-01-2010", это не вызовет никаких исключений .......... Просто запустите его на своей машине и посмотрите ... это не так Работа....

sasidhar 24.12.2010 23:01

Виноват. Я удалил свой комментарий. Но второе утверждение вызывает для меня исключение. @duffymo - какой jvm вы используете?

Aravind Yarram 24.12.2010 23:08

@Pangea, я использую jdk1.6.0_23 Я пробовал это с этим, даже joda-time.sourceforge.net, но даже это не сработало ....

sasidhar 24.12.2010 23:13

Что не сработало? Попробуйте выполнить sys out of date 2 и разместить здесь то, что печатается. Пробовал с 1.6.0_20-b02.

Aravind Yarram 24.12.2010 23:33

Исключение в потоке «main» java.text.ParseException: неразборчивая дата: «31-02-2010» в java.text.DateFormat.parse (DateFormat.java:337)

Aravind Yarram 24.12.2010 23:39

@maximus: это потому, что первый сгенерировал исключение, и, следовательно, остаток кода не будет выполнен. @sasidhar: это потому, что 31 января - допустимая дата. @duffymo: подумайте о том, чтобы поместить каждого в try-catch, чтобы оба были выполнены;)

BalusC 25.12.2010 00:30

Я понимаю, что это всего лишь простой тест, но чтобы просто убедиться, что люди не копируют это дословно, я хочу сказать, что «DateFormat» НЕ БЕЗОПАСЕН ДЛЯ ПОТОКОВ. Поэтому всегда создавайте его как локальную переменную или используйте с локальным потоком.

Aravind Yarram 25.12.2010 01:24

@Pangea только что выяснила, что 31 февраля не генерирует исключение, если мы используем формат даты как «дд-мм-гггг», это должно быть «дд-мм-гггг», это была мелочь, которая беспокоила меня в течение нескольких дней. , только что заметил, что я использую маленькую букву в течение месяца, в любом случае спасибо. Есть идеи, что означает маленькая м?

sasidhar 25.12.2010 08:42

маленький m используется для обозначения минут. кажется, SimpleDateFormat более снисходителен, чем хотелось бы ;-). Посмотрите здесь поддерживаемые символы и их интерпретации: mboshart.dyndns.org/boshart/documentation/APIdocs/api/java/t‌ ext /…

Aravind Yarram 25.12.2010 08:50

Ключ - df.setLenient (ложь);. Для простых случаев этого более чем достаточно. Если вы ищете более надежные (я сомневаюсь) и / или альтернативные библиотеки, такие как joda-time, посмотрите ответ пользователя "tardate"

final static String DATE_FORMAT = "dd-MM-yyyy";

public static boolean isDateValid(String date) 
{
        try {
            DateFormat df = new SimpleDateFormat(DATE_FORMAT);
            df.setLenient(false);
            df.parse(date);
            return true;
        } catch (ParseException e) {
            return false;
        }
}

Попробуйте с «09-04-201а». Это создаст безумное свидание.

ceklock 10.04.2014 04:44

@ceklock, как это работает, независимо от того, используете ли вы setLenient или нет: SimpleDateFormat всегда будет анализировать, пока шаблон не будет сопоставлен, и игнорирует остальную часть строки, таким образом, вы получаете 201 как год.

Daniel Naber 04.06.2014 17:48

@ceklock Я только что обратился к нему в мое решение. Это может сэкономить пару минут для кого-то.

Sufian 29.05.2015 14:56

Включение обработки исключений влечет за собой большой удар производительности, поэтому это, вероятно, плохой дизайн, ЕСЛИ вы ожидаете неправильного ввода при нормальной работе (например, при проверке пользовательского ввода). Но если метод используется для двойной проверки входных данных, которые должны быть действительными все время (за исключением ошибок), это нормально.

Aaron 04.09.2015 22:59

К вашему сведению, ужасно неприятные старые классы даты и времени, такие как java.util.Date, java.util.Calendar и java.text.SimpleDateFormat, теперь являются наследие, вытесненными классами java.time, встроенными в Java 8 и новее. См. Руководство от Oracle.

Basil Bourque 11.08.2018 21:37

Вышеупомянутые методы синтаксического анализа даты хороши, я просто добавил новую проверку в существующие методы, которые дважды проверяют преобразованную дату с исходной датой с помощью средства форматирования, поэтому он работает почти для каждого случая, как я проверял. например 29.02.2013 неверная дата. Данная функция анализирует дату в соответствии с текущими допустимыми форматами даты. Он возвращает истину, если дата не была успешно проанализирована.

 public final boolean validateDateFormat(final String date) {
        String[] formatStrings = {"MM/dd/yyyy"};
        boolean isInvalidFormat = false;
        Date dateObj;
        for (String formatString : formatStrings) {
            try {
                SimpleDateFormat sdf = (SimpleDateFormat) DateFormat.getDateInstance();
                sdf.applyPattern(formatString);
                sdf.setLenient(false);
                dateObj = sdf.parse(date);
                System.out.println(dateObj);
                if (date.equals(sdf.format(dateObj))) {
                    isInvalidFormat = false;
                    break;
                }
            } catch (ParseException e) {
                isInvalidFormat = true;
            }
        }
        return isInvalidFormat;
    }

Предлагаю вам использовать класс org.apache.commons.validator.GenericValidator от apache.

GenericValidator.isDate(String value, String datePattern, boolean strict);

Примечание: strict - должно ли быть точное совпадение datePattern.

Это отлично работает для меня. Подход, предложенный выше Беном.

private static boolean isDateValid(String s) {
    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
    try {
        Date d = asDate(s);
        if (sdf.format(d).equals(s)) {
            return true;
        } else {
            return false;
        }
    } catch (ParseException e) {
        return false;
    }
}

не могу распознать asDate. Это что?

Susheel 23.09.2015 01:04

java.time

Благодаря классам Дата и время API (java.time), встроенным в Java 8 и более поздних версий, вы можете использовать класс LocalDate.

public static boolean isDateValid(int year, int month, int day) {
    boolean dateIsValid = true;
    try {
        LocalDate.of(year, month, day);
    } catch (DateTimeException e) {
        dateIsValid = false;
    }
    return dateIsValid;
}

По умолчанию в этом коде используется ResolverStyle.SMART, который настраивает полученное значение на допустимую дату, а не генерирует исключение. Таким образом, этот код не достигнет цели Вопроса. См., Например, мой ответ и решение с использованием ResolverStyle.STRICT.

Basil Bourque 23.09.2016 01:30

Основываясь на Ответ Аравинда, чтобы исправить проблему, указанную ceklock в его комментарии, я добавил метод для проверки того, что dateString не содержит недопустимых символов.

Вот как я это делаю:

private boolean isDateCorrect(String dateString) {
    try {
        Date date = mDateFormatter.parse(dateString);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return matchesOurDatePattern(dateString);    //added my method
    }
    catch (ParseException e) {
        return false;
    }
}

/**
 * This will check if the provided string matches our date format
 * @param dateString
 * @return true if the passed string matches format 2014-1-15 (YYYY-MM-dd)
 */
private boolean matchesDatePattern(String dateString) {
    return dateString.matches("^\\d+\\-\\d+\\-\\d+");
}

Я думаю, что проще всего просто преобразовать строку в объект даты и преобразовать ее обратно в строку. Данная строка даты подходит, если обе строки все еще совпадают.

public boolean isDateValid(String dateString, String pattern)
{   
    try
    {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        if (sdf.format(sdf.parse(dateString)).equals(dateString))
            return true;
    }
    catch (ParseException pe) {}

    return false;
}

Вот что я сделал для среды Node без внешних библиотек:

Date.prototype.yyyymmdd = function() {
   var yyyy = this.getFullYear().toString();
   var mm = (this.getMonth()+1).toString(); // getMonth() is zero-based
   var dd  = this.getDate().toString();
   return zeroPad([yyyy, mm, dd].join('-'));  
};

function zeroPad(date_string) {
   var dt = date_string.split('-');
   return dt[0] + '-' + (dt[1][1]?dt[1]:"0"+dt[1][0]) + '-' + (dt[2][1]?dt[2]:"0"+dt[2][0]);
}

function isDateCorrect(in_string) {
   if (!matchesDatePattern) return false;
   in_string = zeroPad(in_string);
   try {
      var idate = new Date(in_string);
      var out_string = idate.yyyymmdd();
      return in_string == out_string;
   } catch(err) {
      return false;
   }

   function matchesDatePattern(date_string) {
      var dateFormat = /[0-9]+-[0-9]+-[0-9]+/;
      return dateFormat.test(date_string); 
   }
}

А вот как им пользоваться:

isDateCorrect('2014-02-23')
true

tl; dr

Используйте строгий режим на java.time.DateTimeFormatter, чтобы проанализировать LocalDate. Ловушка для DateTimeParseException.

LocalDate.parse(                   // Represent a date-only value, without time-of-day and without time zone.
    "31/02/2000" ,                 // Input string.
    DateTimeFormatter              // Define a formatting pattern to match your input string.
    .ofPattern ( "dd/MM/uuuu" )
    .withResolverStyle ( ResolverStyle.STRICT )  // Specify leniency in tolerating questionable inputs.
)

После синтаксического анализа вы можете проверить разумное значение. Например, дата рождения за последние сто лет.

birthDate.isAfter( LocalDate.now().minusYears( 100 ) )

Избегайте устаревших классов даты и времени

Избегайте использования проблемных старых классов даты и времени, поставляемых с самыми ранними версиями Java. Сейчас вытеснены классами java.time.

LocalDate и DateTimeFormatter и ResolverStyle

Класс LocalDate представляет значение только для даты без времени суток и без часового пояса.

String input = "31/02/2000";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd/MM/uuuu" );
try {
    LocalDate ld = LocalDate.parse ( input , f );
    System.out.println ( "ld: " + ld );
} catch ( DateTimeParseException e ) {
    System.out.println ( "ERROR: " + e );
}

Класс java.time.DateTimeFormatter может быть установлен для синтаксического анализа строк с любым из трех режимов смягчения, определенных в перечислении ResolverStyle. Мы вставляем строку в приведенный выше код, чтобы попробовать каждый из режимов.

f = f.withResolverStyle ( ResolverStyle.LENIENT );

Результаты:

  • ResolverStyle.LENIENT
    ld: 2000-03-02
  • ResolverStyle.SMART
    ld: 2000-02-29
  • ResolverStyle.STRICT
    ОШИБКА: java.time.format.DateTimeParseException: текст «31/02/2000» не может быть проанализирован: недопустимая дата «31 февраля»

Мы видим, что в режиме ResolverStyle.LENIENT недопустимая дата перемещается вперед на эквивалентное количество дней. В режиме ResolverStyle.SMART (по умолчанию) принимается логическое решение сохранить дату в пределах месяца и использовать последний возможный день месяца, 29 февраля високосного года, поскольку в этом месяце нет 31-го дня. Режим ResolverStyle.STRICT выдает исключение с жалобой на отсутствие такой даты.

Все три варианта разумны в зависимости от вашей бизнес-задачи и политики. Похоже, в вашем случае вы хотите, чтобы строгий режим отклонял недопустимую дату, а не настраивал ее.


Table of all date-time types in Java, both modern and legacy.


О java.time

Фреймворк java.time встроен в Java 8 и новее. Эти классы заменяют неудобные старые классы даты и времени наследие, такие как java.util.Date, Calendar, & SimpleDateFormat.

Чтобы узнать больше, см. Учебник Oracle. И поищите в Stack Overflow множество примеров и объяснений. Спецификация - JSR 310.

Проект Джода-Тайм, теперь в Режим обслуживания, советует перейти на классы java.time.

Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте Драйвер JDBC, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в классах java.sql.*.

Где взять классы java.time?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с объединенной реализацией.
    • В Java 9 добавлены некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport.
  • Android
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). См. Как использовать ThreeTenABP….

Table of which java.time library to use with which version of Java or Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательной площадкой для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и более.

Что ж, предположим, что проект компилируется с использованием java 8+, тогда ваш ответ правильный. Я тоже использую эти классы, когда проект находится на java 8. Но иногда мне приходится трогать эти уродливые древние скриптлеты jsp (которые даже не поддерживают java 7). Проверка дат - это сложная задача. Значит, я здесь. И все же ваш ответ - наиболее правильный подход ... Вывод: я облажался.

KarelG 19.04.2017 14:37

@KarelG Перечитайте предпоследний абзац о бэк-порт на Java 6 и Java 7. Я не проверял это поведение в бэк-порте, но предлагаю вам попробовать.

Basil Bourque 19.04.2017 14:44
// to return valid days of month, according to month and year
int returnDaysofMonth(int month, int year) {
    int daysInMonth;
    boolean leapYear;
    leapYear = checkLeap(year);
    if (month == 4 || month == 6 || month == 9 || month == 11)
        daysInMonth = 30;
    else if (month == 2)
        daysInMonth = (leapYear) ? 29 : 28;
    else
        daysInMonth = 31;
    return daysInMonth;
}

// to check a year is leap or not
private boolean checkLeap(int year) {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, year);
    return cal.getActualMaximum(Calendar.DAY_OF_YEAR) > 365;
}

Вот я бы проверил формат даты:

 public static boolean checkFormat(String dateTimeString) {
    return dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}") || dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}")
            || dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}") || dateTimeString
            .matches("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z") ||
            dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}Z");
}

Для этой работы у нас есть современный java.time классы. Написание сложного регулярного выражения - вряд ли лучшее использование вашего времени. См. Однострочник в мой ответ.

Basil Bourque 01.11.2018 01:43
        public static String detectDateFormat(String inputDate, String requiredFormat) {
        String tempDate = inputDate.replace("/", "").replace("-", "").replace(" ", "");
        String dateFormat;

        if (tempDate.matches("([0-12]{2})([0-31]{2})([0-9]{4})")) {
            dateFormat = "MMddyyyy";
        } else if (tempDate.matches("([0-31]{2})([0-12]{2})([0-9]{4})")) {
            dateFormat = "ddMMyyyy";
        } else if (tempDate.matches("([0-9]{4})([0-12]{2})([0-31]{2})")) {
            dateFormat = "yyyyMMdd";
        } else if (tempDate.matches("([0-9]{4})([0-31]{2})([0-12]{2})")) {
            dateFormat = "yyyyddMM";
        } else if (tempDate.matches("([0-31]{2})([a-z]{3})([0-9]{4})")) {
            dateFormat = "ddMMMyyyy";
        } else if (tempDate.matches("([a-z]{3})([0-31]{2})([0-9]{4})")) {
            dateFormat = "MMMddyyyy";
        } else if (tempDate.matches("([0-9]{4})([a-z]{3})([0-31]{2})")) {
            dateFormat = "yyyyMMMdd";
        } else if (tempDate.matches("([0-9]{4})([0-31]{2})([a-z]{3})")) {
            dateFormat = "yyyyddMMM";
        } else {
            return "Pattern Not Added";
//add your required regex
        }
        try {
            String formattedDate = new SimpleDateFormat(requiredFormat, Locale.ENGLISH).format(new SimpleDateFormat(dateFormat).parse(tempDate));

            return formattedDate;
        } catch (Exception e) {
            //
            return "";
        }

    }

setLenient в false, если вам нравится строгая проверка

public boolean isThisDateValid(String dateToValidate, String dateFromat){

    if (dateToValidate == null){
        return false;
    }

    SimpleDateFormat sdf = new SimpleDateFormat(dateFromat);
    sdf.setLenient(false);

    try {

        //if not valid, it will throw ParseException
        Date date = sdf.parse(dateToValidate);
        System.out.println(date);

    } catch (ParseException e) {

        e.printStackTrace();
        return false;
    }

    return true;
}

похоже, что SimpleDateFormat не проверяет шаблон строго даже после применения к нему метода setLenient (ложь);, поэтому я использовал метод ниже, чтобы проверить, является ли введенная дата действительной датой или нет в соответствии с предоставленным шаблоном.

import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
public boolean isValidFormat(String dateString, String pattern) {
    boolean valid = true;
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
    try {
        formatter.parse(dateString);
    } catch (DateTimeParseException e) {
        valid = false;
    }
    return valid;
}

С «устаревшим» форматом даты мы можем отформатировать результат и сравнить его с исходным.

    public boolean isValidFormat(String source, String pattern) {
    SimpleDateFormat sd = new SimpleDateFormat(pattern);
    sd.setLenient(false);
    try {
        Date date = sd.parse(source);
        return date != null && sd.format(date).equals(source);
    } catch (Exception e) {
        return false;
    }
}

В этом отрывке указано «false» для source = 01.01.04 с шаблоном «01. 01.2004».

Другие вопросы по теме