정신적 방법 Java의 날짜를 확인하십시오
-
03-07-2019 - |
문제
나는 가장 명백한 것을 만드는 것이 궁금하다는 것을 알았습니다. 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- 더 나은 대안?
나는 듣고 있었다 조다 시간 최근에 내가 비교할 것이라고 생각했다. 두 가지 점 :
- SimpledateFormat와 달리 날짜 문자열의 잘못된 문자에 대해 엄격한 것 같습니다.
- 아직 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-02ResolverStyle.SMART
LD : 2000-02-29ResolverStyle.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 수업을 어디에서 얻을 수 있습니까?
- Java SE 8, Java SE 9, 그리고 나중에
- 내장.
- 번들 구현이있는 표준 Java API의 일부.
- Java 9는 사소한 기능과 수정 사항을 추가합니다.
- Java SE 6 그리고 Java SE 7
- Java.Time 기능의 대부분은 Java 6 & 7으로 백 포트되어 있습니다. Threeten-Backport.
- 기계적 인조 인간
- Java.Time 클래스의 이후 버전의 Android 번들 구현.
- 이전 안드로이드 (<26)의 경우 threetenabp 프로젝트 적응 Threeten-Backport (위에 언급했듯이). 보다 Threetenabp를 사용하는 방법….
그만큼 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");
}