2010-01-27 11 views
39

Sadece bir Java masaüstü uygulamasında bir girdinin tam olarak "YYYY-AA-GG" biçiminde biçimlendirilmiş bir dizgenin olduğunu doğrulamak için bir yolun (belki de normal ifadeyle) olup olmadığını merak ediyorum.Java üzerinde regex tarih formatı onayı

Hiç aramadım ama başarılı olamadım.

+6

Aylar ve günler için herhangi bir yıl ve geçersiz sayılara izin vermek ister misiniz? Örneğin 9999-99-99? 2009-02-29 gibi geçersiz tarihler ne olacak? –

+0

İlgili soru, yalnızca Regex: http: // stackoverflow.com/q/8647893/8384 – McKay

cevap

62

kullanın aşağıdaki normal ifade teşekkürler:

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

matches yöntemle

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

olduğu gibi çapalar ^ ve $ (sırasıyla başlangıç ​​ve dize sonu) örtülü olarak mevcut.

+3

Ancak, bu yalnızca geçerli tarihin geçerli olmadığı tarih biçimini doğrular. Daha fazla B/B fikrini çok beğeniyorum ya da doğru hatırlıyorsa, ortak validasyon paketinde de iyi bir validasyon olmalıdır. –

+2

Tarihler zor. Girişin FORMAT'ını doğrulayabilmenize rağmen, CONTENT'i basit bir normal ifade ile doğrulayamazsınız. Görev için oluşturulmuş bir çözümleyici kullanmanızı öneririz. –

+0

@ChrisNava önerilir, evet. Düzenli olarak tarih doğrulama yapmak mümkündür. Ama tavsiye edilmez. http://stackoverflow.com/q/8647893/8384 – McKay

29

regex'dan daha fazlasına ihtiyacınız var, örneğin "9999-99-00" geçerli bir tarih değil. Bunu yapmak için geliştirilmiş bir SimpleDateFormat sınıfı var. Daha ağır, ama daha kapsamlı.

örn.

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

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

Maalesef SimpleDateFormat ağır ve evresel değildir hem de.

+15

SimpleDateFormat geçersiz tarihleri ​​reddetmek istiyorsanız 'setLenient (false)' öğesini çağırmayı unutmayın. Kodunuz "9999-99-00" kabul edecektir ('' Feb 28 00:00:00 CET 10007'') –

+1

Teşekkür ederim Carlos, 2009-20-20 gibi girdileri tanıyacağını bile bilmiyordum. Teşekkürler :) – Sheldon

+0

ve başka bir nokta: SimpleDateFormat formatı kontrol etmez: "2010-1-8", "10-001-002", ... kabul edilecektir –

2

maske ile bir SimpleDateFormat Construct ve sonra çağrı: SimpleDateFormat.parse (String s, ParsePosition p) ince kontrolü için

+0

2 argümanı yerine 1 argüman yöntemini "ayrıştırma (String)" olarak adlandırmanız yeterlidir. _ _ _ SimpleDateFormat geçersiz tarihleri ​​reddetmek istiyorsanız 'setLenient (false)' seçeneğini de unutmayın. –

1

, SimpleDateFormat("YYYY-MM-dd") Steve B. tarafından önerilen

22

koymak kullanarak InputVerifier düşünün Hepsini birbirine:

  • REGEX
  • ("2010-19-19" gibi) değerlerini doğrulamazbiçimini kontrol etmez ("2010/01/02", "1-0002-003" kabul edilir)

hem biçim ve değer doğrulamak için kullanmak gereklidir:

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; 
    } 
} 



A ThreadLocal, her çağrı için yeni bir SimpleDateFormat oluşturulmasını önlemek için kullanılabilir.
SimpleDateFormat parçacığı güvenli değil çünkü çoklu işlemli kapsamında gereklidir:

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; 
    } 
} 

+0

regex değerleri doğrulayabilir – McKay

11

Bu yapacağım regex (aynı zamanda iş parçacığı güvenli değil bir eşleştirici için yapılabilir): "^((19|20)\\d\\d)-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$" Geçerli biçimler ve geçerli tarihler ile ilgilenir. Ayın doğru günleri, yani artık yıl geçerli olmaz.

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")); 

İyi şanslar!

7
Ben gün en fazla 12 şey gibi fazla 31 gün ve ay yok kontrol edeceğini de basit bir regex ile gider

:

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

Bu biçim "gg-AA- olduğunu yyyy". İhtiyaçlarınıza göre ayarlayabilir (örneğin, baştaki 0'ı zorunlu hale getirmek için - şimdi isteğe bağlıdır) ve daha sonra, özel bir mantığı kullanarak, geçen yıllar gibi, belirli bir kurala göre kesebilirsiniz. ayların gün sayısı vakaları. Aşağıdaki DateChecker kodunu görün.

Bu yaklaşımı seçiyorum çünkü performansın göz önüne alındığında bunun en iyi olduğunu test ettim. Bu (1) yaklaşımını, diğer kullanım durumları ile ilgilenen bir regex'e karşı bir tarihin onaylanmasına ilişkin ikinci yaklaşıma karşı, ve SimpleDateFormat.parse (tarih) ile birlikte yukarıdaki aynı basit ifadeyi kullanmanın 3. yaklaşımıyla karşılaştırdım.
İlk yaklaşım, 2. yaklaşımdan 4 kat daha hızlıydı ve 3. yaklaşımdan 8 kat daha hızlıydı. Alt kısımda bulunan tarih kontrol cihazı ve performans test cihazı ana sınıfına bakın. İşaretlemeden ayrıldığım bir şey, joda zaman yaklaşımıdır. (Daha verimli tarih/saat kütüphanesi).

tarihi denetleyicisi kodu:

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(); 
    } 
} 

Tarih denetimi/test ve performans testi:

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(); 
     } 
    } 
} 

Bazı yararlı notlar:
- iddialarını (çek iddia) Kullanmak gerek sağlamak için - test cihazını çalıştırırken argüman. (Tutulma sırasında bu, Çalıştır/Hata Ayıklama yapılandırması -> Bağımsız Değişkenler sekmesi -> VM Bağımsız Değişkenleri -> "--ea"
'u ekleyerek yapılır - yukarıdaki normal ifade 1800 - 2199 arası
- sınırlı kalmazsınız. Başlangıçta^ve en sonunda tüm tarih dizgisini eşleştirmek için kullanın. String.matches bununla ilgilenir.
- geçerli ve geçersiz durumları kontrol ettiğinizden ve bunları sahip olduğunuz kurallara göre değiştirdiğinizden emin olun.
- her bir regex'in "sadece bütün dizgisi" sürümü, "normal" sürümüyle aynı hızı verir (^ ve $ olmayan bir) .Bu performans farklarını görürseniz, java'nın aynı talimatları işlemek için "kullanıldığından" bunun nedeni budur. zaman azalır Eğer "normal" ve "sadece bütün dizi" versiyonunun uygulandığı satırları değiştirirseniz, bunu ispatlarsınız.

Bu birinin işe yaramasını umarız!
Alkış,
Despot

+1

http://stackoverflow.com/questions/1905551/how-can-i-make-simpledateformat-parse-fail-when-month-is-greater-than-12 – BalusC

+0

Hey BalusC - bu doğrudur:), SimpleDateFormat.parse en geçersiz tarihleri ​​kapsayacak şekilde yapabilirsiniz. Bu yaklaşımı "Tarih kontrol/test ve performans testi" bölümünde test ettim. 001-0002-00003 gibi geçersiz tarihleri ​​kapsamaz. (Sanırım geçersiz olduğunu düşündüğünüze göre değişir - benim durumumda bu geçersiz bir tarihti). Gördüğünüz gibi bu yaklaşım en yavaş olanıdır (3. yaklaşımı tartıştığımda yazıyı kontrol edin). Ayrıca, Test Cihazını sizin tarafınızdan çalıştırmak ve zamanları görmekte özgürsünüz;) – despot

+0

başka bir ipucu - eğer regex kapağını 1900'den 9999'a kadar yapmak istiyorsanız, bunun 3. grup olması gerekir: (([^ 01]) [0-9] | 19 | [2-9] [0-9]) \\ d \\ d) – despot

0

Java 8+ kullanarak tarih/saat doğrulama yapmak için uygun (ve kolay) yolu java.time.format.DateTimeFormatter sınıf kullanmaktır. Doğrulama için bir regex kullanmak, tarihler için gerçekten ideal değildir. Bu, söz konusu örnek durum için: Bu kod metnini ayrıştırmak olacak

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 
} 

, bu geçerli bir tarih olduğunu ve aynı zamanda bir LocalDate nesnesi olarak döndürür doğrulamak. Kullanım durumunuz bunlardan herhangi biri ile eşleşiyorsa, DateTimeFormatter sınıfının ISO standartları ile eşleşen birtakım statik önceden tanımlanmış tarih biçimlerine sahip olduğunu unutmayın.