2015-09-28 85 views
13

我想在客户端验证日期,所以我写了下面的代码。但是,我得到一个适当的日期对象为2月31日的日期字符串,这显然是一个无效的日期,而不是得到一个异常。Java 8 LocalDateTime解析无效日期

public class Test { 

    public static void main(String[] args) { 
     String dateFormat = "HH:mm:ss MM/dd/yyyy"; 
     String dateString = "11:30:59 02/31/2015"; 
     DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US); 
     try { 
      LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter); 
      System.out.println(date); 
     } catch (Exception e) { 
      // Throw invalid date message 
     } 
    } 
} 

输出:2015-02-28T11:30:59

有谁知道为什么LocalDateTime在解析这个日期,而不是抛出异常。

+0

你为什么要等待异常? – Andrew

+2

@AndrewTobilko,大概是因为2月31日不存在。 – aioobe

+0

但格式化程序不知道这一点。 – Satya

回答

21

你只需要一个严格的ResolverStyle

解析文本字符串发生在两个阶段。根据添加到构建器的字段,阶段1是基本的文本解析。阶段2将解析的字段值对解析为日期和/或时间对象。这种风格用于控制第2阶段如何解决问题。

示例代码 - 在withResolverStyle(ResolverStyle.STRICT)是重要的变化,使用的uuuu而非yyyy沿(其中uuuu是“年”和“YYYY”是“时代的一年”,因此暧昧):

import java.time.*; 
import java.time.format.*; 
import java.util.*; 

public class Test { 

    public static void main(String[] args) { 
     String dateFormat = "HH:mm:ss MM/dd/uuuu"; 
     String dateString = "11:30:59 02/31/2015"; 
     DateTimeFormatter dateTimeFormatter = DateTimeFormatter 
      .ofPattern(dateFormat, Locale.US) 
      .withResolverStyle(ResolverStyle.STRICT); 
     try { 
      LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter); 
      System.out.println(date); 
     } catch (DateTimeParseException e) { 
      // Throw invalid date message 
      System.out.println("Exception was thrown"); 
     } 
    } 
} 
+3

将格式字符串中的yyyy更改为uuuu,然后不需要混淆ERA – Palamino

+0

@Palamino:Aha!很好,谢谢。 –

0

LocalDateTime.parse将只抛出一个错误,如果传递的字符串包含无效字符,天数超过31或一个月的超过12

例如,如果你修改了代码,例如:

String dateString = "11:30:59 0zz2/31/2015"; 

由于给定日期内无效的'zz'字符会引发异常。至于为什么它是“舍入”日期可以说,我不知道。

来源:https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#parse-java.lang.CharSequence-

+0

正确注意并纠正了RealSkeptic。 – jste89

2
try { 
    SimpleDateFormat df = new java.text.SimpleDateFormat("HH:mm:ss MM/dd/yyyy"); 
    df.setLenient(false); 
    System.out.println(df.parse("11:30:59 02/29/2015")); 
} catch (java.text.ParseException e) { 
    System.out.println(e); 
} 

我找到了一个解决方案来识别日期与DateFormat.setLenient(boolean)有效日期。如果你尝试解析任何无效的日期,它会抛出解析异常。

编辑:

Java 8,但这将引发异常,如果一个月不112之间,如果每天超过32。确实没有工作。但一个月的工作。

try { 
TemporalAccessor ta = DateTimeFormatter.ofPattern("HH:mm:ss MM/dd/yyyy").parse("11:30:59 02/32/2015"); 
} catch (Exception e) { 
System.out.println(e); 
} 

输出:

java.time.format.DateTimeParseException: Text '11:30:59 02/32/2015' could not be 
parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 32 
+0

'SimpleDateFormat'不适用于Java 8'LocalDateTime'。我正在寻找Java8 LocalDateTime的解决方案 – Zeeshan

7

Java的8 DateTimeFormatter采用YYYY意味着YEAR_OF_ERA,并UUUU意味着一年。您需要修改你的模式字符串如下:

String dateFormat = "HH:mm:ss MM/dd/uuuu"; 

的DateTimeFormatter默认使用SMART解析器风格,但你希望它使用严格的解析器风格。修改您的dateTimeFormatter初始化代码,如下所示:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US) 
                 .withResolverStyle(ResolverStyle.STRICT); 
2

它并没有舍去。 2月份从未有过31天,并且不可能使用验证日期/时间对象来表示不存在的日子。

因此,它将采用无效输入并为您提供正确日期(当年2月的最后一个日期)的最佳近似值。

SimpleDateFormat继承自DateFormat其上有一个setLenient(boolean value)方法。我希望如果在解析之前调用setLenient(true),它可能会抱怨更多,as detailed in the javadocs