如何在 Java 中检查日期
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/226910/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to sanity check a date in Java
提问by Bloodboiler
I find it curious that the most obvious way to create Date
objects in Java has been deprecated and appears to have been "substituted" with a not so obvious to use lenient calendar.
我觉得奇怪的是,Date
在 Java 中创建对象的最明显的方法已被弃用,并且似乎已被不太明显的使用宽松日历“取代”。
How do you check that a date, given as a combination of day, month, and year, is a valid date?
您如何检查以日、月和年的组合形式给出的日期是否是有效日期?
For instance, 2008-02-31 (as in yyyy-mm-dd) would be an invalid date.
例如,2008-02-31(如 yyyy-mm-dd)将是无效日期。
采纳答案by AdamC
The current way is to use the calendar class. It has the setLenientmethod that will validate the date and throw and exception if it is out of range as in your example.
目前的方法是使用日历类。它具有setLenient方法,该方法将验证日期并在超出范围时抛出异常,如您的示例所示。
Forgot to add: If you get a calendar instance and set the time using your date, this is how you get the validation.
忘记添加:如果您获得日历实例并使用您的日期设置时间,这就是您获得验证的方式。
Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.setTime(yourDate);
try {
cal.getTime();
}
catch (Exception e) {
System.out.println("Invalid date");
}
回答by Maglob
You can use SimpleDateFormat
您可以使用SimpleDateFormat
For example something like:
例如类似的东西:
boolean isLegalDate(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setLenient(false);
return sdf.parse(s, new ParsePosition(0)) != null;
}
回答by tardate
As shown by @Maglob, the basic approach is to test the conversion from string to date using SimpleDateFormat.parse. That will catch invalid day/month combinations like 2008-02-31.
如@Maglob 所示,基本方法是使用SimpleDateFormat.parse测试从字符串到日期的转换。这将捕获无效的日/月组合,如 2008-02-31。
However, in practice that is rarely enough since SimpleDateFormat.parse is exceedingly liberal. There are two behaviours you might be concerned with:
然而,实际上这还不够,因为 SimpleDateFormat.parse 是非常自由的。您可能会关注两种行为:
Invalid characters in the date stringSurprisingly, 2008-02-2x will "pass" as a valid date with locale format = "yyyy-MM-dd" for example. Even when isLenient==false.
日期字符串中的无效字符令人惊讶的是,例如,2008-02-2x 将“通过”作为区域设置格式 =“yyyy-MM-dd”的有效日期。即使isLenient==false。
Years: 2, 3 or 4 digits?You may also want to enforce 4-digit years rather than allowing the default SimpleDateFormat behaviour (which will interpret "12-02-31" differently depending on whether your format was "yyyy-MM-dd" or "yy-MM-dd")
年数:2、3 或 4 位数字?您可能还想强制使用 4 位数年份而不是允许默认的 SimpleDateFormat 行为(这将根据您的格式是“yyyy-MM-dd”还是“yy-MM-dd”而不同地解释“12-02-31” )
A Strict Solution with the Standard Library
标准库的严格解决方案
So a complete string to date test could look like this: a combination of regex match, and then a forced date conversion. The trick with the regex is to make it locale-friendly.
因此,完整的字符串到日期测试可能如下所示:正则表达式匹配的组合,然后是强制日期转换。正则表达式的诀窍是使其对语言环境友好。
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);
Note that the regex assumes the format string contains only day, month, year, and separator characters. Aside from that, format can be in any locale format: "d/MM/yy", "yyyy-MM-dd", and so on. The format string for the current locale could be obtained like this:
请注意,正则表达式假定格式字符串仅包含日、月、年和分隔符。除此之外,格式可以是任何语言环境格式:“d/MM/yy”、“yyyy-MM-dd”等等。当前语言环境的格式字符串可以这样获得:
Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );
String format = sdf.toPattern();
Joda Time - Better Alternative?
Joda Time - 更好的选择?
I've been hearing about joda timerecently and thought I'd compare. Two points:
我最近听说了joda 时间,我想我会比较一下。两点:
- Seems better at being strict about invalid characters in the date string, unlike SimpleDateFormat
- Can't see a way to enforce 4-digit years with it yet (but I guess you could create your own DateTimeFormatterfor this purpose)
- 与 SimpleDateFormat 不同,在严格限制日期字符串中的无效字符方面似乎更好
- 还看不到强制使用 4 位数年份的方法(但我想您可以为此创建自己的DateTimeFormatter)
It's quite simple to use:
使用起来非常简单:
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;
}
回答by Tom
Two comments on the use of SimpleDateFormat.
关于 SimpleDateFormat 的使用的两条评论。
it should be declared as a static instance if declared as static access should be synchronized as it is not thread safe
如果声明为静态访问,则应将其声明为静态实例,因为它不是线程安全的
IME that is better that instantiating an instance for each parse of a date.
IME 比为日期的每个解析实例化一个实例更好。
回答by Ben
An alternative strict solution using the standard library is to perform the following:
使用标准库的另一种严格解决方案是执行以下操作:
1) Create a strict SimpleDateFormat using your pattern
1) 使用您的模式创建一个严格的 SimpleDateFormat
2) Attempt to parse the user entered value using the format object
2) 尝试使用格式对象解析用户输入的值
3) If successful, reformat the Date resulting from (2) using the same date format (from (1))
3)如果成功,使用相同的日期格式(来自(1))重新格式化由(2)产生的日期
4) Compare the reformatted date against the original, user-entered value. If they're equal then the value entered strictly matches your pattern.
4) 将重新格式化的日期与用户输入的原始值进行比较。如果它们相等,则输入的值与您的模式严格匹配。
This way, you don't need to create complex regular expressions - in my case I needed to support all of SimpleDateFormat's pattern syntax, rather than be limited to certain types like just days, months and years.
这样,您不需要创建复杂的正则表达式 - 在我的情况下,我需要支持 SimpleDateFormat 的所有模式语法,而不是仅限于某些类型,例如几天、几个月和几年。
回答by duffymo
Assuming that both of those are Strings (otherwise they'd already be valid Dates), here's one way:
假设这两个都是字符串(否则它们已经是有效的日期),这是一种方法:
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);
}
}
Here's the output I get:
这是我得到的输出:
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
As you can see, it does handle both of your cases nicely.
如您所见,它确实可以很好地处理您的两种情况。
回答by Aravind Yarram
Key is df.setLenient(false);. This is more than enough for simple cases. If you are looking for a more robust (I doubt) and/or alternate libraries like joda-time then look at the answer by the user "tardate"
关键是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;
}
}
回答by Imran
Above methods of date parsing are nice , i just added new check in existing methods that double check the converted date with original date using formater, so it works for almost each case as i verified. e.g. 02/29/2013 is invalid date. Given function parse the date according to current acceptable date formats. It returns true if date is not parsed successfully.
上面的日期解析方法很好,我只是在现有方法中添加了新的检查,这些方法使用格式化程序对转换后的日期与原始日期进行双重检查,因此它几乎适用于我验证的每种情况。例如 02/29/2013 是无效日期。给定函数根据当前可接受的日期格式解析日期。如果未成功解析日期,则返回 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;
}
回答by Ziya
I suggest you to use org.apache.commons.validator.GenericValidator
class from apache.
我建议你使用org.apache.commons.validator.GenericValidator
apache 的类。
GenericValidator.isDate(String value, String datePattern, boolean strict);
GenericValidator.isDate(String value, String datePattern, boolean strict);
Note: strict - Whether or not to have an exact match of the datePattern.
注意:strict - 是否与 datePattern 完全匹配。
回答by Dresden Sparrow
This is working great for me. Approach suggested above by Ben.
这对我很有用。Ben 上面建议的方法。
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;
}
}