문제

나는 가장 명백한 것을 만드는 것이 궁금하다는 것을 알았습니다. Date Java의 물체는 더 이상 사용되지 않았으며 관대 한 달력을 사용하는 것이 분명하지 않은 것으로 "대체"된 것으로 보입니다.

요일, 월 및 연도의 조합으로 주어진 날짜가 유효한 날짜인지 어떻게 확인합니까?

예를 들어, 2008-02-31 (YYYY-MM-DD에서와 같이)은 잘못된 날짜입니다.

도움이 되었습니까?

해결책

현재 방법은 캘린더 클래스를 사용하는 것입니다. 그것은 있습니다 setlenient 예제에서와 같이 범위를 벗어난 날짜 및 던지기 및 예외를 유효성있게하는 방법.

추가를 잊어 버렸습니다. 달력 인스턴스를 얻고 날짜를 사용하여 시간을 설정하면 검증을받는 방법입니다.

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

다른 팁

키는 df.setLenient (false);. 이것은 간단한 경우에 충분합니다. 더 강력한 (의심스러운) 및/또는 Joda-Time과 같은 대체 라이브러리를 찾고 있다면 사용자 "지각"에 의한 답변

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

@Maglob에서 보여주는 바와 같이, 기본 접근법은 문자열에서 최신으로 전환을 테스트하는 것입니다. simpledateformat.parse. 그것은 2008-02-31과 같은 무효 일/월 조합을 포착 할 것입니다.

그러나 실제로 SimpledateFormat.parse가 매우 자유롭기 때문에 거의 충분하지 않습니다. 다음과 같은 두 가지 행동이 있습니다.

날짜 문자열의 잘못된 문자놀랍게도, 2008-02-2x는 예를 들어 로케일 형식 = "yyyy-mm-dd"의 유효한 날짜로 "통과"합니다. Islenient == False 일 때에도.

연도 : 2, 3 또는 4 자리?또한 기본 SimpledateFormat 동작을 허용하지 않고 4 자리 연도를 시행 할 수도 있습니다 (이는 형식이 "YYYY-MM-DD"또는 "YY-MM-DD"인지 여부에 따라 다르게 "12-02-31"을 해석합니다. )

표준 라이브러리가있는 엄격한 솔루션

따라서 현재까지의 완전한 문자열 테스트는 다음과 같습니다. Regex Match의 조합 및 강제 날짜 변환. Regex의 트릭은 로케일 친화적으로 만드는 것입니다.

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

REGEX는 형식 문자열에 하루, 월, 연도 및 분리기 문자 만 포함한다고 가정합니다. 그 외에도 형식은 "d/mm/yy", "yyyy-mm-dd"등 모든 로케일 형식 일 수 있습니다. 현재 로케일의 형식 문자열은 다음과 같이 얻을 수 있습니다.

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

Joda Time- 더 나은 대안?

나는 듣고 있었다 조다 시간 최근에 내가 비교할 것이라고 생각했다. 두 가지 점 :

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

당신이 사용할 수있는 SimpledateFormat

예를 들어 :

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

tl; dr

사용 엄격한 모드 ~에 java.time.DateTimeFormatter 구문 분석 a LocalDate. TRAP 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.
)

구문 분석 후 합리적인 가치를 확인할 수 있습니다. 예를 들어, 지난 100 년 이내의 생년월일.

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 : text '31/02/2000 '은 구문 분석 할 수 없습니다 : 유효하지 않은 날짜'2 월 31 일 '

우리는 그것을 볼 수 있습니다 ResolverStyle.LENIENT 모드에서, 유효하지 않은 날짜는 동등한 일로 전달됩니다. ~ 안에 ResolverStyle.SMART 모드 (기본값), 해당 달의 날짜를 유지하기 위해 논리적 결정이 이루어집니다. 그 달에는 31 일이 없기 때문에 2 월 29 일에 2 월 29 일에 29 월 29 일에 가야합니다. 그만큼 ResolverStyle.STRICT 모드는 그러한 날짜가 없다고 불평하는 예외를 던집니다.

이 세 가지 모두 비즈니스 문제와 정책에 따라 합리적입니다. 당신의 경우에 당신은 엄격한 모드를 조정하기보다는 잘못된 날짜를 거부하기를 원합니다.


에 대한 Java.Time

그만큼 Java.Time 프레임 워크는 Java 8 이상에 내장되어 있습니다. 이 수업은 번거로운 오래된 것을 대체합니다 유산 다음과 같은 날짜 시간 수업 java.util.Date, Calendar, & SimpleDateFormat.

그만큼 조다-시간 지금 프로젝트 유지 관리 모드, Java.Time 클래스.

자세한 내용은 오라클 튜토리얼. 많은 예와 설명에 대한 검색 스택 오버 플로우. 사양입니다 JSR 310.

교환 할 수 있습니다 Java.Time 데이터베이스와 직접 개체. a JDBC 드라이버 준수합니다 JDBC 4.2 또는 나중에. 문자열이 필요없고 필요하지 않습니다 java.sql.* 클래스.

Java.Time 수업을 어디에서 얻을 수 있습니까?

그만큼 Threeten-extra 프로젝트는 추가 클래스로 Java.Time을 연장합니다. 이 프로젝트는 Java.Time에 향후 추가 할 수있는 근거입니다. 여기에서 유용한 수업을 찾을 수 있습니다 Interval, YearWeek, YearQuarter, 그리고 .

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

표준 라이브러리를 사용하는 대체 엄격한 솔루션은 다음을 수행하는 것입니다.

1) 패턴을 사용하여 엄격한 SimpledateFormat을 만듭니다

2) 형식 개체를 사용하여 사용자를 입력 한 값을 구문 분석하려고 시도

3) 성공한 경우 (2) 동일한 날짜 형식을 사용하여 ((1))를 사용하여 날짜를 재구성합니다.

4) 개혁 된 날짜를 원래의 사용자 입력 값과 비교하십시오. 그것들이 같으면 입력 된 값은 패턴과 엄격하게 일치합니다.

이런 식으로, 당신은 복잡한 정규 표현식을 만들 필요가 없습니다. 제 경우에는 며칠, 달 및 몇 년과 같은 특정 유형으로 제한되지 않고 SimpledateFormat의 패턴 구문을 모두 지원해야했습니다.

답을 바탕으로 @pangea 지적한 문제를 해결하기 위해 @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+");
}

나는 당신이 사용하는 것이 좋습니다 org.apache.commons.validator.GenericValidator 아파치에서 수업.

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

참고 : 엄격한 - 날짜 패터 넷과 정확히 일치하는지 여부.

나는 단순한 것이 문자열을 날짜 개체로 변환하여 문자열로 다시 변환하는 것이라고 생각합니다. 주어진 날짜 문자열은 두 줄이 여전히 일치하면 괜찮습니다.

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

두 가지가 현으로 끈이라고 가정하면 (그렇지 않으면 이미 유효한 날짜) 다음과 같은 방법이 있습니다.

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

보시다시피, 그것은 두 경우를 모두 잘 처리합니다.

이것은 나를 위해 잘 작동합니다. 벤이 위에서 제안한 접근법.

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

SimpledateFormat 사용에 대한 두 가지 의견.

정적 액세스로 선언 된 경우 스레드 안전하지 않으므로 동기화되어야하는 경우 정적 인스턴스로 선언해야합니다.

날짜의 각 구획에 대한 인스턴스를 인스턴스화하는 것이 좋습니다.

위의 방법 구문 분석이 좋으면 Formater를 사용하여 원래 날짜로 변환 된 날짜를 두 번 확인하는 기존 메소드에 새 확인이 추가되었으므로 확인대로 거의 각 사례에 대해 작동합니다. 예 : 2013 년 2 월 29 일은 잘못된 날짜입니다. 주어진 함수는 현재 허용 가능한 날짜 형식에 따라 날짜를 구문 분석합니다. 날짜가 성공적으로 구문 분석되지 않으면 TRUE가 반환됩니다.

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

외부 라이브러리가없는 노드 환경에서 내가 한 일은 다음과 같습니다.

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
// 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");
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top