Java 上的正则表达式日期格式验证

我只是想知道是否有一种方法(也许可以用正则表达式)来验证 Java 桌面应用程序上的输入确实是一个格式为“ YYYY-MM-DD”的字符串。

267578 次浏览

使用以下正则表达式:

^\d{4}-\d{2}-\d{2}$

就是

if (str.matches("\\d{4}-\\d{2}-\\d{2}")) {
...
}

使用 matches方法,可以隐式地显示锚 ^$(分别是字符串的开始和结束)。

上面的模式检查与日期的一般“形状”是否一致,但是它将接受比有效日期更无效的日期。您可能会惊讶地发现,检查有效日期ーー包括闰年!ー是使用正则表达式的 有可能,但不建议这样做。从 库尔迪普在其他地方给出的答案中,我们都可以找到对于坚持的乐趣和钦佩

((18|19|20)[0-9]{2}[\-.](0[13578]|1[02])[\-.](0[1-9]|[12][0-9]|3[01]))|(18|19|20)[0-9]{2}[\-.](0[469]|11)[\-.](0[1-9]|[12][0-9]|30)|(18|19|20)[0-9]{2}[\-.](02)[\-.](0[1-9]|1[0-9]|2[0-8])|(((18|19|20)(04|08|[2468][048]|[13579][26]))|2000)[\-.](02)[\-.]29

在生产环境中,您的同事会欣赏更直接的实现。记住,优化的第一条规则是不要!

您需要的不仅仅是 regex,例如“9999-99-00”不是有效日期。有一个 SimpleDateFormat类就是为此而构建的。更重量级,但更全面。

例如:。

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");


boolean isValidDate(string input) {
try {
format.parse(input);
return true;
}
catch(ParseException e){
return false;
}
}

不幸的是,SimpleDateFormat既是重量级的,又不是线程安全的。

使用掩码构造一个 SimpleDateFormat,然后调用: Parse (String s,ParsePosition p)

为了更好的控制,考虑使用史蒂夫 B 建议的 SimpleDateFormat("YYYY-MM-dd")输入验证程序

总而言之:

  • REGEX不验证值(如“2010-19-19”)
  • SimpleDateFormat不检查格式(接受“2010-1-2”、“1-0002-003”)

有必要同时使用以验证格式和值:

public static boolean isValid(String text) {
if (text == null || !text.matches("\\d{4}-[01]\\d-[0-3]\\d"))
return false;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
df.setLenient(false);
try {
df.parse(text);
return true;
} catch (ParseException ex) {
return false;
}
}



ThreadLocal 可用于避免为每个调用创建新的 SimpleDateFormat。
由于 SimpleDateFormat 不是线程安全的,因此需要在多线程上下文中使用它:

private static final ThreadLocal<SimpleDateFormat> format = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
df.setLenient(false);
System.out.println("created");
return df;
}
};


public static boolean isValid(String text) {
if (text == null || !text.matches("\\d{4}-[01]\\d-[0-3]\\d"))
return false;
try {
format.get().parse(text);
return true;
} catch (ParseException ex) {
return false;
}
}

(对于 Matcher 也可以这样做,它也不是线程安全的)

正则表达式: "^((19|20)\\d\\d)-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$" 这将处理有效的格式和有效的日期。它不会验证该月份的正确日期,即闰年。

String regex = "^((19|20)\\d\\d)-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$";


Assert.assertTrue("Date: matched.", Pattern.matches(regex, "2011-1-1"));
Assert.assertFalse("Date (month): not matched.", Pattern.matches(regex, "2011-13-1"));

祝你好运!

我会选择一个简单的 regex,它可以检查天数不超过31天,月数不超过12个。比如:

(0?[1-9]|[12][0-9]|3[01])-(0?[1-9]|1[012])-((18|19|20|21)\\d\\d)

这是格式“ dd-MM-yyyy”。你可以根据自己的需要进行调整(例如,去掉?使前导0成为必需的-现在它是可选的) ,然后使用一个自定义逻辑来减少到特定的规则,如闰年二月天数的情况下,其他月份天数的情况。请参见下面的 DateChecker 代码。

我之所以选择这种方法,是因为我测试过,当考虑到性能时,这是最好的方法。我检查了第一种方法和第二种方法,第二种方法是根据处理其他用例的正则表达式验证日期,第三种方法是结合 SimpleDateFormat.parse (date)使用相同的简单正则表达式。
第一种方法比第二种方法快4倍,比第三种方法快8倍。查看底部自包含的日期检查器和性能测试器主类。 我没有选中的一个方法是 joda time 方法(更有效的日期/时间库)。

日期检查代码:

class DateChecker {


private Matcher matcher;
private Pattern pattern;


public DateChecker(String regex) {
pattern = Pattern.compile(regex);
}


/**
* Checks if the date format is a valid.
* Uses the regex pattern to match the date first.
* Than additionally checks are performed on the boundaries of the days taken the month into account (leap years are covered).
*
* @param date the date that needs to be checked.
* @return if the date is of an valid format or not.
*/
public boolean check(final String date) {
matcher = pattern.matcher(date);
if (matcher.matches()) {
matcher.reset();
if (matcher.find()) {
int day = Integer.parseInt(matcher.group(1));
int month = Integer.parseInt(matcher.group(2));
int year = Integer.parseInt(matcher.group(3));


switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: return day < 32;
case 4:
case 6:
case 9:
case 11: return day < 31;
case 2:
int modulo100 = year % 100;
//http://science.howstuffworks.com/science-vs-myth/everyday-myths/question50.htm
if ((modulo100 == 0 && year % 400 == 0) || (modulo100 != 0 && year % LEAP_STEP == 0)) {
//its a leap year
return day < 30;
} else {
return day < 29;
}
default:
break;
}
}
}
return false;
}


public String getRegex() {
return pattern.pattern();
}
}

日期检查/测试及性能测试:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class Tester {


private static final String[] validDateStrings = new String[]{
"1-1-2000", //leading 0s for day and month optional
"01-1-2000", //leading 0 for month only optional
"1-01-2000", //leading 0 for day only optional
"01-01-1800", //first accepted date
"31-12-2199", //last accepted date
"31-01-2000", //January has 31 days
"31-03-2000", //March has 31 days
"31-05-2000", //May has 31 days
"31-07-2000", //July has 31 days
"31-08-2000", //August has 31 days
"31-10-2000", //October has 31 days
"31-12-2000", //December has 31 days
"30-04-2000", //April has 30 days
"30-06-2000", //June has 30 days
"30-09-2000", //September has 30 days
"30-11-2000", //November has 30 days
};
private static final String[] invalidDateStrings = new String[]{
"00-01-2000", //there is no 0-th day
"01-00-2000", //there is no 0-th month
"31-12-1799", //out of lower boundary date
"01-01-2200", //out of high boundary date
"32-01-2000", //January doesn't have 32 days
"32-03-2000", //March doesn't have 32 days
"32-05-2000", //May doesn't have 32 days
"32-07-2000", //July doesn't have 32 days
"32-08-2000", //August doesn't have 32 days
"32-10-2000", //October doesn't have 32 days
"32-12-2000", //December doesn't have 32 days
"31-04-2000", //April doesn't have 31 days
"31-06-2000", //June doesn't have 31 days
"31-09-2000", //September doesn't have 31 days
"31-11-2000", //November doesn't have 31 days
"001-02-2000", //SimpleDateFormat valid date (day with leading 0s) even with lenient set to false
"1-0002-2000", //SimpleDateFormat valid date (month with leading 0s) even with lenient set to false
"01-02-0003", //SimpleDateFormat valid date (year with leading 0s) even with lenient set to false
"01.01-2000", //. invalid separator between day and month
"01-01.2000", //. invalid separator between month and year
"01/01-2000", /// invalid separator between day and month
"01-01/2000", /// invalid separator between month and year
"01_01-2000", //_ invalid separator between day and month
"01-01_2000", //_ invalid separator between month and year
"01-01-2000-12345", //only whole string should be matched
"01-13-2000", //month bigger than 13
};


/**
* These constants will be used to generate the valid and invalid boundary dates for the leap years. (For no leap year, Feb. 28 valid and Feb. 29 invalid; for a leap year Feb. 29 valid and Feb. 30 invalid)
*/
private static final int LEAP_STEP = 4;
private static final int YEAR_START = 1800;
private static final int YEAR_END = 2199;


/**
* This date regex will find matches for valid dates between 1800 and 2199 in the format of "dd-MM-yyyy".
* The leading 0 is optional.
*/
private static final String DATE_REGEX = "((0?[1-9]|[12][0-9]|3[01])-(0?[13578]|1[02])-(18|19|20|21)[0-9]{2})|((0?[1-9]|[12][0-9]|30)-(0?[469]|11)-(18|19|20|21)[0-9]{2})|((0?[1-9]|1[0-9]|2[0-8])-(0?2)-(18|19|20|21)[0-9]{2})|(29-(0?2)-(((18|19|20|21)(04|08|[2468][048]|[13579][26]))|2000))";


/**
* This date regex is similar to the first one, but with the difference of matching only the whole string. So "01-01-2000-12345" won't pass with a match.
* Keep in mind that String.matches tries to match only the whole string.
*/
private static final String DATE_REGEX_ONLY_WHOLE_STRING = "^" + DATE_REGEX + "$";


/**
* The simple regex (without checking for 31 day months and leap years):
*/
private static final String DATE_REGEX_SIMPLE = "(0?[1-9]|[12][0-9]|3[01])-(0?[1-9]|1[012])-((18|19|20|21)\\d\\d)";


/**
* This date regex is similar to the first one, but with the difference of matching only the whole string. So "01-01-2000-12345" won't pass with a match.
*/
private static final String DATE_REGEX_SIMPLE_ONLY_WHOLE_STRING = "^" + DATE_REGEX_SIMPLE + "$";


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


private static final DateChecker dateValidatorSimple = new DateChecker(DATE_REGEX_SIMPLE);
private static final DateChecker dateValidatorSimpleOnlyWholeString = new DateChecker(DATE_REGEX_SIMPLE_ONLY_WHOLE_STRING);


/**
* @param args
*/
public static void main(String[] args) {
DateTimeStatistics dateTimeStatistics = new DateTimeStatistics();
boolean shouldMatch = true;
for (int i = 0; i < validDateStrings.length; i++) {
String validDate = validDateStrings[i];
matchAssertAndPopulateTimes(
dateTimeStatistics,
shouldMatch, validDate);
}


shouldMatch = false;
for (int i = 0; i < invalidDateStrings.length; i++) {
String invalidDate = invalidDateStrings[i];


matchAssertAndPopulateTimes(dateTimeStatistics,
shouldMatch, invalidDate);
}


for (int year = YEAR_START; year < (YEAR_END + 1); year++) {
FebruaryBoundaryDates februaryBoundaryDates = createValidAndInvalidFebruaryBoundaryDateStringsFromYear(year);
shouldMatch = true;
matchAssertAndPopulateTimes(dateTimeStatistics,
shouldMatch, februaryBoundaryDates.getValidFebruaryBoundaryDateString());
shouldMatch = false;
matchAssertAndPopulateTimes(dateTimeStatistics,
shouldMatch, februaryBoundaryDates.getInvalidFebruaryBoundaryDateString());
}


dateTimeStatistics.calculateAvarageTimesAndPrint();
}


private static void matchAssertAndPopulateTimes(
DateTimeStatistics dateTimeStatistics,
boolean shouldMatch, String date) {
dateTimeStatistics.addDate(date);
matchAndPopulateTimeToMatch(date, DATE_REGEX, shouldMatch, dateTimeStatistics.getTimesTakenWithDateRegex());
matchAndPopulateTimeToMatch(date, DATE_REGEX_ONLY_WHOLE_STRING, shouldMatch, dateTimeStatistics.getTimesTakenWithDateRegexOnlyWholeString());
boolean matchesSimpleDateFormat = matchWithSimpleDateFormatAndPopulateTimeToMatchAndReturnMatches(date, dateTimeStatistics.getTimesTakenWithSimpleDateFormatParse());
matchAndPopulateTimeToMatchAndReturnMatchesAndCheck(
dateTimeStatistics.getTimesTakenWithDateRegexSimple(), shouldMatch,
date, matchesSimpleDateFormat, DATE_REGEX_SIMPLE);
matchAndPopulateTimeToMatchAndReturnMatchesAndCheck(
dateTimeStatistics.getTimesTakenWithDateRegexSimpleOnlyWholeString(), shouldMatch,
date, matchesSimpleDateFormat, DATE_REGEX_SIMPLE_ONLY_WHOLE_STRING);


matchAndPopulateTimeToMatch(date, dateValidatorSimple, shouldMatch, dateTimeStatistics.getTimesTakenWithdateValidatorSimple());
matchAndPopulateTimeToMatch(date, dateValidatorSimpleOnlyWholeString, shouldMatch, dateTimeStatistics.getTimesTakenWithdateValidatorSimpleOnlyWholeString());
}


private static void matchAndPopulateTimeToMatchAndReturnMatchesAndCheck(
List<Long> times,
boolean shouldMatch, String date, boolean matchesSimpleDateFormat, String regex) {
boolean matchesFromRegex = matchAndPopulateTimeToMatchAndReturnMatches(date, regex, times);
assert !((matchesSimpleDateFormat && matchesFromRegex) ^ shouldMatch) : "Parsing with SimpleDateFormat and date:" + date + "\nregex:" + regex + "\nshouldMatch:" + shouldMatch;
}


private static void matchAndPopulateTimeToMatch(String date, String regex, boolean shouldMatch, List<Long> times) {
boolean matches = matchAndPopulateTimeToMatchAndReturnMatches(date, regex, times);
assert !(matches ^ shouldMatch) : "date:" + date + "\nregex:" + regex + "\nshouldMatch:" + shouldMatch;
}


private static void matchAndPopulateTimeToMatch(String date, DateChecker dateValidator, boolean shouldMatch, List<Long> times) {
long timestampStart;
long timestampEnd;
boolean matches;
timestampStart = System.nanoTime();
matches = dateValidator.check(date);
timestampEnd = System.nanoTime();
times.add(timestampEnd - timestampStart);
assert !(matches ^ shouldMatch) : "date:" + date + "\ndateValidator with regex:" + dateValidator.getRegex() + "\nshouldMatch:" + shouldMatch;
}


private static boolean matchAndPopulateTimeToMatchAndReturnMatches(String date, String regex, List<Long> times) {
long timestampStart;
long timestampEnd;
boolean matches;
timestampStart = System.nanoTime();
matches = date.matches(regex);
timestampEnd = System.nanoTime();
times.add(timestampEnd - timestampStart);
return matches;
}


private static boolean matchWithSimpleDateFormatAndPopulateTimeToMatchAndReturnMatches(String date, List<Long> times) {
long timestampStart;
long timestampEnd;
boolean matches = true;
timestampStart = System.nanoTime();
try {
SDF.parse(date);
} catch (ParseException e) {
matches = false;
} finally {
timestampEnd = System.nanoTime();
times.add(timestampEnd - timestampStart);
}
return matches;
}


private static FebruaryBoundaryDates createValidAndInvalidFebruaryBoundaryDateStringsFromYear(int year) {
FebruaryBoundaryDates februaryBoundaryDates;
int modulo100 = year % 100;
//http://science.howstuffworks.com/science-vs-myth/everyday-myths/question50.htm
if ((modulo100 == 0 && year % 400 == 0) || (modulo100 != 0 && year % LEAP_STEP == 0)) {
februaryBoundaryDates = new FebruaryBoundaryDates(
createFebruaryDateFromDayAndYear(29, year),
createFebruaryDateFromDayAndYear(30, year)
);
} else {
februaryBoundaryDates = new FebruaryBoundaryDates(
createFebruaryDateFromDayAndYear(28, year),
createFebruaryDateFromDayAndYear(29, year)
);
}
return februaryBoundaryDates;
}


private static String createFebruaryDateFromDayAndYear(int day, int year) {
return String.format("%d-02-%d", day, year);
}


static class FebruaryBoundaryDates {
private String validFebruaryBoundaryDateString;
String invalidFebruaryBoundaryDateString;
public FebruaryBoundaryDates(String validFebruaryBoundaryDateString,
String invalidFebruaryBoundaryDateString) {
super();
this.validFebruaryBoundaryDateString = validFebruaryBoundaryDateString;
this.invalidFebruaryBoundaryDateString = invalidFebruaryBoundaryDateString;
}
public String getValidFebruaryBoundaryDateString() {
return validFebruaryBoundaryDateString;
}
public void setValidFebruaryBoundaryDateString(
String validFebruaryBoundaryDateString) {
this.validFebruaryBoundaryDateString = validFebruaryBoundaryDateString;
}
public String getInvalidFebruaryBoundaryDateString() {
return invalidFebruaryBoundaryDateString;
}
public void setInvalidFebruaryBoundaryDateString(
String invalidFebruaryBoundaryDateString) {
this.invalidFebruaryBoundaryDateString = invalidFebruaryBoundaryDateString;
}
}


static class DateTimeStatistics {
private List<String> dates = new ArrayList<String>();
private List<Long> timesTakenWithDateRegex = new ArrayList<Long>();
private List<Long> timesTakenWithDateRegexOnlyWholeString = new ArrayList<Long>();
private List<Long> timesTakenWithDateRegexSimple = new ArrayList<Long>();
private List<Long> timesTakenWithDateRegexSimpleOnlyWholeString = new ArrayList<Long>();
private List<Long> timesTakenWithSimpleDateFormatParse = new ArrayList<Long>();
private List<Long> timesTakenWithdateValidatorSimple = new ArrayList<Long>();
private List<Long> timesTakenWithdateValidatorSimpleOnlyWholeString = new ArrayList<Long>();
public List<String> getDates() {
return dates;
}
public List<Long> getTimesTakenWithDateRegex() {
return timesTakenWithDateRegex;
}
public List<Long> getTimesTakenWithDateRegexOnlyWholeString() {
return timesTakenWithDateRegexOnlyWholeString;
}
public List<Long> getTimesTakenWithDateRegexSimple() {
return timesTakenWithDateRegexSimple;
}
public List<Long> getTimesTakenWithDateRegexSimpleOnlyWholeString() {
return timesTakenWithDateRegexSimpleOnlyWholeString;
}
public List<Long> getTimesTakenWithSimpleDateFormatParse() {
return timesTakenWithSimpleDateFormatParse;
}
public List<Long> getTimesTakenWithdateValidatorSimple() {
return timesTakenWithdateValidatorSimple;
}
public List<Long> getTimesTakenWithdateValidatorSimpleOnlyWholeString() {
return timesTakenWithdateValidatorSimpleOnlyWholeString;
}
public void addDate(String date) {
dates.add(date);
}
public void addTimesTakenWithDateRegex(long time) {
timesTakenWithDateRegex.add(time);
}
public void addTimesTakenWithDateRegexOnlyWholeString(long time) {
timesTakenWithDateRegexOnlyWholeString.add(time);
}
public void addTimesTakenWithDateRegexSimple(long time) {
timesTakenWithDateRegexSimple.add(time);
}
public void addTimesTakenWithDateRegexSimpleOnlyWholeString(long time) {
timesTakenWithDateRegexSimpleOnlyWholeString.add(time);
}
public void addTimesTakenWithSimpleDateFormatParse(long time) {
timesTakenWithSimpleDateFormatParse.add(time);
}
public void addTimesTakenWithdateValidatorSimple(long time) {
timesTakenWithdateValidatorSimple.add(time);
}
public void addTimesTakenWithdateValidatorSimpleOnlyWholeString(long time) {
timesTakenWithdateValidatorSimpleOnlyWholeString.add(time);
}


private void calculateAvarageTimesAndPrint() {
long[] sumOfTimes = new long[7];
int timesSize = timesTakenWithDateRegex.size();
for (int i = 0; i < timesSize; i++) {
sumOfTimes[0] += timesTakenWithDateRegex.get(i);
sumOfTimes[1] += timesTakenWithDateRegexOnlyWholeString.get(i);
sumOfTimes[2] += timesTakenWithDateRegexSimple.get(i);
sumOfTimes[3] += timesTakenWithDateRegexSimpleOnlyWholeString.get(i);
sumOfTimes[4] += timesTakenWithSimpleDateFormatParse.get(i);
sumOfTimes[5] += timesTakenWithdateValidatorSimple.get(i);
sumOfTimes[6] += timesTakenWithdateValidatorSimpleOnlyWholeString.get(i);
}
System.out.println("AVG from timesTakenWithDateRegex (in nanoseconds):" + (double) sumOfTimes[0] / timesSize);
System.out.println("AVG from timesTakenWithDateRegexOnlyWholeString (in nanoseconds):" + (double) sumOfTimes[1] / timesSize);
System.out.println("AVG from timesTakenWithDateRegexSimple (in nanoseconds):" + (double) sumOfTimes[2] / timesSize);
System.out.println("AVG from timesTakenWithDateRegexSimpleOnlyWholeString (in nanoseconds):" + (double) sumOfTimes[3] / timesSize);
System.out.println("AVG from timesTakenWithSimpleDateFormatParse (in nanoseconds):" + (double) sumOfTimes[4] / timesSize);
System.out.println("AVG from timesTakenWithDateRegexSimple + timesTakenWithSimpleDateFormatParse (in nanoseconds):" + (double) (sumOfTimes[2] + sumOfTimes[4]) / timesSize);
System.out.println("AVG from timesTakenWithDateRegexSimpleOnlyWholeString + timesTakenWithSimpleDateFormatParse (in nanoseconds):" + (double) (sumOfTimes[3] + sumOfTimes[4]) / timesSize);
System.out.println("AVG from timesTakenWithdateValidatorSimple (in nanoseconds):" + (double) sumOfTimes[5] / timesSize);
System.out.println("AVG from timesTakenWithdateValidatorSimpleOnlyWholeString (in nanoseconds):" + (double) sumOfTimes[6] / timesSize);
}
}


static class DateChecker {


private Matcher matcher;
private Pattern pattern;


public DateChecker(String regex) {
pattern = Pattern.compile(regex);
}


/**
* Checks if the date format is a valid.
* Uses the regex pattern to match the date first.
* Than additionally checks are performed on the boundaries of the days taken the month into account (leap years are covered).
*
* @param date the date that needs to be checked.
* @return if the date is of an valid format or not.
*/
public boolean check(final String date) {
matcher = pattern.matcher(date);
if (matcher.matches()) {
matcher.reset();
if (matcher.find()) {
int day = Integer.parseInt(matcher.group(1));
int month = Integer.parseInt(matcher.group(2));
int year = Integer.parseInt(matcher.group(3));


switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: return day < 32;
case 4:
case 6:
case 9:
case 11: return day < 31;
case 2:
int modulo100 = year % 100;
//http://science.howstuffworks.com/science-vs-myth/everyday-myths/question50.htm
if ((modulo100 == 0 && year % 400 == 0) || (modulo100 != 0 && year % LEAP_STEP == 0)) {
//its a leap year
return day < 30;
} else {
return day < 29;
}
default:
break;
}
}
}
return false;
}


public String getRegex() {
return pattern.pattern();
}
}
}

一些有用的注意事项:
- 启用您需要使用的断言(断言检查)-在运行测试程序时使用 ea 参数。(在 eclipse 中,这是通过编辑 Run/Debug 配置-> Arguments tab-> VM Arguments-> insert“-ea”来完成的
- 上述正则表达式以1800年至2199年为界
- 您不需要在开头和结尾使用 ^ 来匹配整个日期字符串。String.match 会处理这个问题。
- 确保检查有效和无效的案件,并根据规则进行修改。
- 每个正则表达式的“唯一完整字符串”版本提供与“正常”版本(没有 ^ 和 $的那个)相同的速度。如果你看到性能差异,这是因为 java“习惯”处理相同的指令,所以时间降低。如果您切换“普通”和“唯一的整个字符串”版本执行的行,您将看到这个证明。

希望这对谁有帮助!
干杯,
暴君

爪哇时间

使用 Java8 + 进行日期/时间验证的正确(且简单)方法是使用 java.time.format.DateTimeFormatter类。使用正则表达式进行验证对于日期来说并不理想。对于这个问题中的例子:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");


try {
LocalDate date = formatter.parse(text, LocalDate::from);
} catch (DateTimeParseException e) {
// Thrown if text could not be parsed in the specified format
}

这段代码将解析文本,验证文本是否为有效日期,并将日期作为 LocalDate对象返回。请注意,如果您的用例匹配其中任何一个,那么 DateTimeFormatter类有许多静态预定义的日期格式与 ISO 标准匹配。

如果您想要一个简单的正则表达式,那么它将是不准确的。 Https://www.freeformatter.com/Java-regex-tester.html#ad-output 提供了一个工具来测试你的 Java 正则表达式。此外,在底部,您可以找到一些验证日期的建议正则表达式。

ISO 日期格式(yyyy-mm-dd) :

^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$

ISO 日期格式(yyyy-mm-dd) ,分隔符为’-’或’/’或’或者。强制在日期之间使用相同的分隔符。

^[0-9]{4}([- /.])(((0[13578]|(10|12))\1(0[1-9]|[1-2][0-9]|3[0-1]))|(02\1(0[1-9]|[1-2][0-9]))|((0[469]|11)\1(0[1-9]|[1-2][0-9]|30)))$

美国日期格式(mm/dd/yyyy)

^(((0[13578]|(10|12))/(0[1-9]|[1-2][0-9]|3[0-1]))|(02/(0[1-9]|[1-2][0-9]))|((0[469]|11)/(0[1-9]|[1-2][0-9]|30)))/[0-9]{4}$

24小时运作模式(HH: MM) :

^(20|21|22|23|[01]\d|\d)((:[0-5]\d){1,2})$

祝你好运

下面添加的代码是为我工作,如果你使用模式 好吧。

public boolean isValidDate(String date) {
boolean check;
String date1 = "^(0?[1-9]|[12][0-9]|3[01])-(0?[1-9]|1[012])-([12][0-9]{3})$";
check = date.matches(date1);


return check;
}

下面的正则表达式将接受 YYYY-MM-DD (在1600-2999年范围内)格式化的日期,并考虑闰年:

 ^((?:(?:1[6-9]|2[0-9])\d{2})(-)(?:(?:(?:0[13578]|1[02])(-)31)|((0[1,3-9]|1[0-2])(-)(29|30))))$|^(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(-)02(-)29)$|^(?:(?:1[6-9]|2[0-9])\d{2})(-)(?:(?:0[1-9])|(?:1[0-2]))(-)(?:0[1-9]|1\d|2[0-8])$

例子:

Date regex examples

你可以测试它 给你

注意: 如果你想接受一个数字作为月或日,你可以使用:

 ^((?:(?:1[6-9]|2[0-9])\d{2})(-)(?:(?:(?:0?[13578]|1[02])(-)31)|((0?[1,3-9]|1[0-2])(-)(29|30))))$|^(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(-)0?2(-)29)$|^(?:(?:1[6-9]|2[0-9])\d{2})(-)(?:(?:0?[1-9])|(?:1[0-2]))(-)(?:0?[1-9]|1\d|2[0-8])$

我已经从这个 解决方案开始创建了上面的正则表达式

模式 yyyy-MM-ddLocalDate#parse使用的 默认模式。因此,所有您需要做的就是将您的日期字符串传递给这个方法,并检查它是否被成功解析,或者是否发生了异常。

演示 :

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.stream.Stream;


public class Main {
public static void main(String[] args) {
String[] arr = { "2022-11-29", "0000-00-00", "2022-1-2", "2022-02-29" };
for (String s : arr) {
try {
System.out.println("================================");
System.out.println(LocalDate.parse(s) + " is a valid date ");
} catch (DateTimeParseException e) {
System.out.println(e.getMessage());


// Recommended; so that the caller can handle it appropriately
// throw new IllegalArgumentException("Invalid date");
}
}
}
}

产出 :

================================
2022-11-29 is a valid date
================================
Text '0000-00-00' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 0
================================
Text '2022-1-2' could not be parsed at index 5
================================
Text '2022-02-29' could not be parsed: Invalid date 'February 29' as '2022' is not a leap year

一些重要提示:

  1. java.time类型遵循 ISO 8601标准,因此需要指定 DateTimeFormatter来解析 ISO 8601格式的日期时间字符串。
  2. 2014年3月 Java-8发布的 java.time API 取代了 容易出错的遗留日期时间 API。从那时起,强烈建议使用这个现代的日期时间 API。从 Rel = “ nofollow noReferrer”> Trail: Date Time 了解有关现代 Date-Time API 的更多信息。