В этой статье показано, как использовать регулярное выражение + код для проверки формата даты, поддержки одиночного и начального нулевого формата месяца и дня (1 или 01), проверки 30 или 31 дня месяца и проверки високосного года.
Ниже приведены требования к действительной дате.
- Формат года, 1900, 2099
регулярное выражение - Формат месяца, 1, 01, 2, 02… 12
регулярное выражение - Формат дня, 1, 01…31
регулярное выражение - Високосный год, 29 февраля.
код - Обычный год, 28 дней февраля.
код - 31 День месяца – 1, 3, 5, 7, 8, 10, 12.
код - 30 Дней в месяце – 4, 6, 9, 11,.
код - ISO 8601 ,
гггг-ММ-ддилиуууу-М-д, например, 2020-11-03.регулярное выражение
((?:19|20)[0-9][0-9])-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])
Приведенное выше регулярное выражение может выполнять требования 1, 2, 3 и 8. Для требований 4, 5, 6, 7 нам нужна ручная проверка кода. Допустимый диапазон дат от 1900-01-01 или 1900-1-1 чтобы 2099-12-31 .
1. Регулярное выражение для формата даты, Года, месяца и Дня.
1.1 Регулярное выражение для подтверждения года, принимает 1900-2099 .
(19|20)[0-9][0-9] # explanation 19[0-9][0-9] # 1900-1999 | # ..or 20[0-9][0-9] # 2000-2099
В будущем, если мы хотим поддерживать год, начинающийся с 21xx , обновите регулярное выражение, как показано ниже:
(19|20|21)[0-9][0-9]
1.2 Регулярное выражение для подтверждения месяца, принимает 01-09 (ведущий ноль), 1-9 (однозначная цифра) и 10,11,12 .
0?[1-9]|1[012] # explanation 0?[1-9] # 01-09 or 1-9 | # ..or 1[012] # 10,11,12
1.3 Регулярное выражение для подтверждения дня, принимает 01-09 (ведущий ноль), 1-9 (одна цифра), 10-19 , 20-29 и 30-31 .
0?[1-9]|[12][0-9]|3[01] # explanation 0?[1-9] # 01-09 or 1-9 | # ..or [12][0-9] # 10-19 or 20-29 | # ..or 3[01] # 30, 31
1.4 У нас есть регулярное выражение для года, месяца и дня, попробуйте объединить его с разными разделителями, чтобы сформировать другой формат даты.
Регулярное выражение для проверки формата даты дд/мм/гггг (общее) или d/M/uuuu (форматер даты Java)
# (dd)/(mm)/(yyyy) (0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((?:19|20)[0-9][0-9])
Регулярное выражение для проверки формата даты гггг-мм-дд (общий) или uuuu-Md (форматирование даты Java)
# (yyyy)-(mm)-(dd) ((?:19|20)[0-9][0-9])-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])
Регулярное выражение для проверки формата даты гггг.мм.дд (общий) или уууу. M.d (форматер даты Java)
# (yyyy).(mm).(dd) ((?:19|20)[0-9][0-9])\\.(0?[1-9]|1[012])\\.(0?[1-9]|[12][0-9]|3[01])$
P.S ?: означает совпадение, но не захватывает его. Смотрите ниже #3 Java DateValidator.
2. 30 или 31 день и високосный год.
Теперь мы можем использовать приведенное выше регулярное выражение для записи года, месяца и дня. Позже мы проверим 30 или 31 день месяца и високосный год .
2.1 В течение 30 или 31 дня месяца.
- В течение месяца 1,3,5,7,8,10,12 имеет 31 день.
- На месяц 4,6,9,11 приходится 30 дней.
if ((month.equals("4") || month.equals("6") || month.equals("9") ||
month.equals("04") || month.equals("06") || month.equals("09") ||
month.equals("11")) && day.equals("31")) {
isValid = false;
}
2.2 Для високосного года 366 дней в году, а в феврале 29 дней; Для обычного года 365 дней в году, а в феврале 28 дней.
if (month.equals("2") || month.equals("02")) {
if (day.equals("30") || day.equals("31")) {
isValid = false;
} else if (day.equals("29")) { // feb 29 days? leap year checking
if (!isLeapYear(year)) {
isValid = false;
}
}
}
private static boolean isLeapYear(int year) {
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
}
“Каждый год, который в точности делится на четыре, является високосным годом, за исключением лет, которые в точности делятся на 100, но эти столетние годы являются високосными, если они в точности делятся на 400. Например, 1700, 1800 и 1900 годы не являются високосными, но 1600 и 2000 годы являются високосными”.
Источник: Википедия Високосный год .
3. Средство проверки даты Регулярных Выражений Java
Вот окончательная версия.
package com.mkyong.regex.date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DateValidatorRegex {
// ?: match but don't capture it
// uuuu-M-d
private static final String DATE_PATTERN =
"^((?:19|20)[0-9][0-9])-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$";
private static final Pattern pattern = Pattern.compile(DATE_PATTERN);
public static boolean isValid(final String date) {
boolean result = false;
Matcher matcher = pattern.matcher(date);
if (matcher.matches()) {
// it is a valid date format yyyy-mm-dd
// assign true first, later we will check the leap year and odd or even months
result = true;
// (?:19|20), match but don't capture it, otherwise it will messy the group order
// for example, 2020-2-30, it will create 4 groups.
// group(1) = 2020, group(2) matches (19|20) = 20, group(3) = 2, group(4) = 30
// So, we put (?:19|20), don't capture this group.
int year = Integer.parseInt(matcher.group(1));
// why string? month matches 02 or 2
String month = matcher.group(2);
String day = matcher.group(3);
// 30 or 31 days checking
// only 1,3,5,7,8,10,12 has 31 days
if ((month.equals("4") || month.equals("6") || month.equals("9") ||
month.equals("04") || month.equals("06") || month.equals("09") ||
month.equals("11")) && day.equals("31")) {
result = false;
} else if (month.equals("2") || month.equals("02")) {
if (day.equals("30") || day.equals("31")) {
result = false;
} else if (day.equals("29")) { // leap year? feb 29 days.
if (!isLeapYear(year)) {
result = false;
}
}
}
}
return result;
}
private static boolean isLeapYear(int year) {
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
}
}
4. Модульные тесты
Ниже приведены параметризованные тесты JUnit 5 для вышеуказанных средств проверки данных Java.
package com.mkyong.regex.date;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class DateValidatorTest {
@ParameterizedTest(name = "#{index} - Run test with date = {0}")
@MethodSource("validDateProvider")
void test_date_regex_valid(String date) {
assertTrue(DateValidatorRegex.isValid(date));
}
@ParameterizedTest(name = "#{index} - Run test with date = {0}")
@MethodSource("invalidDateProvider")
void test_date_regex_invalid(String date) {
assertFalse(DateValidatorRegex.isValid(date));
}
static Stream validDateProvider() {
return Stream.of(
"1998-09-30",
"1998-9-30",
"2020-09-1",
"2020-09-01",
"2020-9-1",
"2020-9-01",
"2020-2-29", // leap year
"2020-2-28", // leap year
"2019-2-28", // common year
"2000-02-29", // 2000 is a leap year, % 400 == 0
"1900-02-28", // 1900 is a common year
"2020-07-31",
"2020-08-31",
"2020-06-30",
"1900-01-01",
"2099-12-31");
}
static Stream invalidDateProvider() {
return Stream.of(
"1998-09-31", // invalid day, sep max 30
"1998-11-31", // invalid day, nov max 30
"2008-02-2x", // invalid day 2x
"2008-0x-28", // invalid month 0x
"20xx-02-28", // invalid year 20xx
"20-11-02", // invalid year 20, must be yyyy
"2020/11/02", // invalid date format, yyyy-mm-dd
"2020-11-32", // invalid day, 32
"2020-13-30", // invalid month 13
"2020-A-20", // invalid month A
"2020-2-30", // leap year, feb max 29
"2019-2-29", // common year, feb max 28
"1900-02-29", // 1900 is a common year, feb max 28
"12012-04-05", // support only 4 digits years
" ", // empty
""); // empty
}
}
Все тесты пройдены.
5. Java 8 форматирование даты и времени + стиль преобразования. строгий
Для разработчика с защитой от регулярных выражений рассмотрим Java 8 Форматировщик даты и времени + Решающий стиль. СТРОГОЕ решение для проверки формата даты. Для получения полного примера и модульных тестов, пожалуйста, обратитесь к этой статье – Проверьте, действительна ли дата в Java
public static boolean isValid(final String date) {
boolean valid = false;
try {
// ResolverStyle.STRICT for 30, 31 days checking, and also leap year.
LocalDate.parse(date,
DateTimeFormatter.ofPattern("uuuu-M-d")
.withResolverStyle(ResolverStyle.STRICT)
);
valid = true;
} catch (DateTimeParseException e) {
e.printStackTrace();
valid = false;
}
return valid;
}
Скачать Исходный Код
$клон git $клон git
$cd java-регулярное выражение/дата
Рекомендации
- Википедия – Високосный год
- Википедия ISO 8601
- Форматирование даты и времени javadoc
- Проверьте, действительна ли дата в Java
Оригинал: “https://mkyong.com/regular-expressions/how-to-validate-date-with-regular-expression/”