Java字符串IsValid检查

时间:2019-03-19 20:59:33

标签: java date datetime

您能否指出以下示例给出解析异常的原因。 IDea会找到一个无效的日期,如2月30日

    String str = "20190310022817";

    SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
    sdf.setLenient(false);
    try {
        System.out.println(sdf.parseObject(str));
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

3 个答案:

答案 0 :(得分:2)

字符串"20190310022817"表示2019年3月10日,星期日,2:28:17,由于夏时制而不存在,该字符串在美国于2019年3月10日,星期日,2:00生效。 :00。

这意味着2019年3月10日星期日1:59:59之后的第二个时间是2019年3月10日星期日3:00:00,因此在该日期不存在2:28:17(在此期间也没有其他第二个那个小时)。

您可以调整字符串中表示的时间,也可以识别出该时间间隔不存在并适当地处理异常。

答案 1 :(得分:2)

tl; dr

LocalDateTime
.parse( 
    "20190310022817" , 
    DateTimeFormatter.ofPattern( "uuuuMMddHHmmss" )
)
.atZone(
    ZoneId.of( "America/Montreal" ) 
)

结果是3 AM,而不是2 AM。针对DST进行调整的功能而非错误。

  

2019-03-10T03:28:17-04:00 [美国/蒙特利尔]

如果您的目标是拒绝这样的无效输入,而不是调整,请参见my Answer另一个解释ResolverStyle枚举的问题: LENIENTSMARTSTRICT

避免使用旧的日期时间类

您使用的是可怕的日期时间类,而现代的 java.time 类已取代了几年前的日期时间类。

夏令时(DST)

正如Answer by rgettman中指出的那样,有些疯狂地参加Daylight Saving Time (DST)的司法管辖区在您指定的日期3月10日凌晨2点进行了“提前”弹跳。这在美国和加拿大的大部分地区,甚至其他地区都在发生。有关DST in the United States,请参阅维基百科。

在这些位置,没有凌晨2点。当时钟到达凌晨2点时,时钟会立即跳至凌晨3点。凌晨两点钟不存在。

顺便说一句,DST不是时钟改变的唯一方案。世界各地的政界人士都表现出对自己管辖范围内的UTC补偿产生兴趣的倾向。例如,参见近年来的朝鲜,委内瑞拉,土耳其和俄罗斯。现在,美国的一些州正在选择停止DST废话,尽管有些州正在考虑永久保留DST。关键是,为了可靠地处理日期时间,无论当前做法如何,您都应该始终假设政治人物会在将来的某个时刻进行更改,并相应地进行编码。

您的输入无效(可能)

由于JVM当前默认时区中的DST跳转是隐式应用的,因为您未指示时区,因此您使用的旧类可能会拒绝输入为无效输入。解析有效值的这种严格协议没有错,只是处理无效输入的一种方法。

ZonedDateTime类默认使用另一种方法,并根据需要进行调整。

ZonedDateTime

java.time.ZonedDateTime类了解该时区过去,现在和将来对特定区域的人们使用的UTC偏移的历史记录。这样该课程将自动调整。请务必阅读课程文档,以了解并同意其调整协议。

LocalDateTime

这是一些示例代码。首先,我们将您的输入解析为LocalDateTime,因为您的输入没有任何时区指示或UTC偏移量。这样,LocalDateTime不会不是代表一个时刻,是 not 在时间轴上的一个点。因此,如果已知某个日期和时间是某个时区,我们可以应用ZoneId来获得ZonedDateTime

在此示例中,我们任意选择两个区域来应用,因此您可以看到不同的结果。在美国,DST跳升的日期是3月10日。在法国等许多欧洲国家,跳伞定于3月的最后一天进行。因此,凌晨2点在法国有效,但在美国无效。

String input = "20190310022817";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMddHHmmss" ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

ZoneId zParis = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdtParis = ldt.atZone( zParis ) ;

ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtNewYork = ldt.atZone( zNewYork ) ;

转储到控制台。

System.out.println( "ldt.toString(): " + ldt ) ;
System.out.println( "zdtParis.toString(): " + zdtParis ) ;
System.out.println( "zdtNewYork.toString(): " + zdtNewYork ) ;

运行时。参见此code run live at IdeOne.com。注意这三个输出中的每个小时:

    前两个时间
  • 凌晨2点
  • 最后一个下午3点
  

ldt.toString():2019-03-10T02:28:17

     

zdtParis.toString():2019-03-10T02:28:17 + 01:00 [欧洲/巴黎]

     

zdtNewYork.toString():2019-03-10T03:28:17-04:00 [美国/纽约]

Table of types of date-time class in modern java.time versus legacy.


关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

答案 2 :(得分:0)

在欧洲,输出为Sun Mar 10 02:28:17 CET 2019,因此应首先设置时区。

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault())