Date
Javaでオブジェクトを作成する最も明白な方法が非推奨になり、寛大なカレンダーを使用するのはそれほど明白ではないものに「置き換え」られたように見えるのは不思議です。
日、月、年の組み合わせで指定された日付が有効な日付であることをどのように確認しますか?
たとえば、2008-02-31(yyyy-mm-ddなど)は無効な日付になります。
Date
Javaでオブジェクトを作成する最も明白な方法が非推奨になり、寛大なカレンダーを使用するのはそれほど明白ではないものに「置き換え」られたように見えるのは不思議です。
日、月、年の組み合わせで指定された日付が有効な日付であることをどのように確認しますか?
たとえば、2008-02-31(yyyy-mm-ddなど)は無効な日付になります。
回答:
現在の方法は、calendarクラスを使用することです。それは持っていsetLenientのそれはあなたの例のように、範囲外の場合は、日付とスローと例外を検証する方法を。
追加するのを忘れた:カレンダーインスタンスを取得し、日付を使用して時刻を設定する場合、これが検証を取得する方法です。
Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.setTime(yourDate);
try {
cal.getTime();
}
catch (Exception e) {
System.out.println("Invalid date");
}
java.util.Date
、java.util.Calendar
とjava.text.SimpleDateFormat
今のレガシーに取って代わられ、java.timeの後にJavaの8とに組み込まれたクラス。Oracleによるチュートリアルを参照してください。
キーはdf.setLenient(false);です。。単純なケースではこれで十分です。より堅牢な(疑わしい)ライブラリやjoda-timeのような代替ライブラリを探している場合は、ユーザー「tardate」による回答を見てください。
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;
}
}
setLenient
かどうかに関係なく、そのように機能します。SimpleDateFormat
パターンが一致するまで常に解析し、残りの文字列を無視するため201
、年として取得されます。
java.util.Date
、java.util.Calendar
とjava.text.SimpleDateFormat
今のレガシーに取って代わられ、java.timeのJavaの8に、後に内蔵されたクラス。Oracleによるチュートリアルを参照してください。
@Maglobに示されているように、基本的なアプローチは、SimpleDateFormat.parseを使用して文字列から日付への変換をテストすることです。これにより、2008-02-31のような無効な日/月の組み合わせが検出されます。
ただし、実際には、SimpleDateFormat.parseは非常にリベラルであるため、これで十分になることはめったにありません。懸念される可能性のある動作は2つあります。
日付文字列の無効な文字 驚くべきことに、2008-02-2xは、たとえばロケール形式が「yyyy-MM-dd」の有効な日付として「合格」します。isLenient == falseの場合でも。
年:2、3、または4桁? また、デフォルトのSimpleDateFormat動作(フォーマットが「yyyy-MM-dd」か「yy-MM-dd」かによって「12-02-31」の解釈が異なる)を許可するのではなく、4桁の年を適用することもできます。 )
したがって、完全な文字列から日付へのテストは次のようになります。正規表現の一致と、強制的な日付変換の組み合わせです。正規表現の秘訣は、正規表現をロケールに適したものにすることです。
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);
正規表現は、フォーマット文字列に日、月、年、および区切り文字のみが含まれていることを前提としていることに注意してください。それ以外の形式は、「d / MM / yy」、「yyyy-MM-dd」など、任意のロケール形式にすることができます。現在のロケールのフォーマット文字列は、次のように取得できます。
Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );
String format = sdf.toPattern();
私は最近ジョダタイムについて聞いていて、比較したいと思いました。2つのポイント:
使い方はとても簡単です。
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;
}
Date
、SimpleDateFormat
など)は、今、現代に取って代わられjava.timeのクラス。同様に、Joda -Timeプロジェクトはメンテナンスモードであり、java.timeクラスへの移行をアドバイスします。
SimpleDateFormatを使用できます
たとえば、次のようなものです。
boolean isLegalDate(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setLenient(false);
return sdf.parse(s, new ParsePosition(0)) != null;
}
java.util.Date
、java.util.Calendar
とjava.text.SimpleDateFormat
今のレガシーに取って代わられ、java.timeのJavaの8に、後に内蔵されたクラス。Oracleによるチュートリアルを参照してください。
を解析するには、strictモードをオンにjava.time.DateTimeFormatter
しますLocalDate
。のトラップ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
このクラスは、で定義された3つのリニエンシーモードのいずれかで文字列を解析するように設定することができますResolverStyle
列挙型。上記のコードに行を挿入して、各モードを試します。
f = f.withResolverStyle ( ResolverStyle.LENIENT );
結果:
ResolverStyle.LENIENT
ResolverStyle.SMART
ResolverStyle.STRICT
ResolverStyle.LENIENT
モードでは、無効な日付が同等の日数だけ前に移動していることがわかります。ではResolverStyle.SMART
何の31日がその月に存在しないとして、うるう年でモード(デフォルト)、論理的な決定は、月内の日付を維持するために作られており、月の最後の可能な日と一緒に行く、2月29日。ResolverStyle.STRICT
モードはそのような日が存在しないことを訴えて例外がスローされます。
これらの3つはすべて、ビジネス上の問題とポリシーに応じて合理的です。あなたの場合、厳密モードで無効な日付を調整するのではなく拒否したいようです。
java.timeフレームワークは、Java8以降に組み込まれています。これらのクラスは面倒古い取って代わるレガシーのような日付時刻クラスをjava.util.Date
、Calendar
、& SimpleDateFormat
。
詳細については、Oracleチュートリアルを参照してください。そして、StackOverflowで多くの例と説明を検索してください。仕様はJSR310です。
ジョダタイムプロジェクトは、今でメンテナンスモードへの移行をアドバイスjava.timeのクラス。
java.timeオブジェクトをデータベースと直接交換できます。JDBC4.2以降に準拠したJDBCドライバーを使用してください。文字列もクラスも必要ありません。java.sql.*
java.timeクラスはどこで入手できますか?
ThreeTen-エクストラプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、java.timeに将来追加される可能性のある試験場です。あなたはここにいくつかの有用なクラスのような見つけることがInterval
、YearWeek
、YearQuarter
、および多くを。
で日付と時刻の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;
}
ResolverStyle.SMART
、例外をスローするのではなく、結果の値を有効な日付に調整するを使用します。したがって、このコードは質問の目的を達成しません。たとえば、私の回答とを使用した解決策を参照してくださいResolverStyle.STRICT
。
標準ライブラリを使用する別の厳密な解決策は、以下を実行することです。
1)パターンを使用して厳密なSimpleDateFormatを作成します
2)フォーマットオブジェクトを使用して、ユーザーが入力した値の解析を試みます
3)成功した場合は、(2)の結果の日付を同じ日付形式((1)の)を使用して再フォーマットします。
4)再フォーマットされた日付を、ユーザーが入力した元の値と比較します。それらが等しい場合、入力された値はパターンに厳密に一致します。
このように、複雑な正規表現を作成する必要はありません。私の場合、日、月、年などの特定のタイプに限定するのではなく、SimpleDateFormatのパターン構文をすべてサポートする必要がありました。
上に構築さAravindの答えが指摘し、問題解決する彼のコメントで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+");
}
最も簡単なのは、文字列を日付オブジェクトに変換し、それを文字列に戻すことだと思います。両方の文字列がまだ一致している場合は、指定された日付文字列で問題ありません。
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;
}
それらの両方が文字列であると仮定すると(そうでなければ、それらはすでに有効な日付になっているでしょう)、ここに1つの方法があります:
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は、setLenient(false)の後でも、パターンを厳密にチェックしていないようです。メソッドが適用されているので、以下のメソッドを使用して、入力された日付が有効な日付であるかどうかを、提供されたパターンに従って検証しました。
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
public boolean isValidFormat(String dateString, String pattern) {
boolean valid = true;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
try {
formatter.parse(dateString);
} catch (DateTimeParseException e) {
valid = false;
}
return valid;
}
SimpleDateFormatの使用に関する2つのコメント。
静的アクセスとして宣言する必要がある場合は、スレッドセーフではないため、静的インスタンスとして宣言する必要があります。
日付の解析ごとにインスタンスをインスタンス化するよりも優れたIME。
上記の日付解析の方法は素晴らしいです。フォーマッターを使用して変換された日付を元の日付と再確認する既存の方法に新しいチェックを追加したので、検証したとおり、ほぼすべての場合に機能します。たとえば、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");
}
public static String detectDateFormat(String inputDate, String requiredFormat) {
String tempDate = inputDate.replace("/", "").replace("-", "").replace(" ", "");
String dateFormat;
if (tempDate.matches("([0-12]{2})([0-31]{2})([0-9]{4})")) {
dateFormat = "MMddyyyy";
} else if (tempDate.matches("([0-31]{2})([0-12]{2})([0-9]{4})")) {
dateFormat = "ddMMyyyy";
} else if (tempDate.matches("([0-9]{4})([0-12]{2})([0-31]{2})")) {
dateFormat = "yyyyMMdd";
} else if (tempDate.matches("([0-9]{4})([0-31]{2})([0-12]{2})")) {
dateFormat = "yyyyddMM";
} else if (tempDate.matches("([0-31]{2})([a-z]{3})([0-9]{4})")) {
dateFormat = "ddMMMyyyy";
} else if (tempDate.matches("([a-z]{3})([0-31]{2})([0-9]{4})")) {
dateFormat = "MMMddyyyy";
} else if (tempDate.matches("([0-9]{4})([a-z]{3})([0-31]{2})")) {
dateFormat = "yyyyMMMdd";
} else if (tempDate.matches("([0-9]{4})([0-31]{2})([a-z]{3})")) {
dateFormat = "yyyyddMMM";
} else {
return "Pattern Not Added";
//add your required regex
}
try {
String formattedDate = new SimpleDateFormat(requiredFormat, Locale.ENGLISH).format(new SimpleDateFormat(dateFormat).parse(tempDate));
return formattedDate;
} catch (Exception e) {
//
return "";
}
}
「レガシー」日付形式を使用すると、結果を形式化してソースと比較できます。
public boolean isValidFormat(String source, String pattern) {
SimpleDateFormat sd = new SimpleDateFormat(pattern);
sd.setLenient(false);
try {
Date date = sd.parse(source);
return date != null && sd.format(date).equals(source);
} catch (Exception e) {
return false;
}
}
このexecerptは、パターン「01.01.2004」でsource = 01.01.04に「false」と言います。
厳密な検証が必要な場合は、setLenientをfalseに設定します
public boolean isThisDateValid(String dateToValidate, String dateFromat){
if(dateToValidate == null){
return false;
}
SimpleDateFormat sdf = new SimpleDateFormat(dateFromat);
sdf.setLenient(false);
try {
//if not valid, it will throw ParseException
Date date = sdf.parse(dateToValidate);
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
return false;
}
return true;
}