首页> 疑难解答

Java字符串IsValid检查

withpy 2021-06-19

简介你有没有人指出为什么下面的例子给出了一个解析异常。 IDea是找到一个无效的日期,如Feb 30 String str =“20190310022817”; SimpleDateFormat sdf = new ...

你有没有人指出为什么下面的例子给出了一个解析异常。 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();
    }
2
投票

tl;dr

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

结果是凌晨3点而不是凌晨2点。调整DST的功能,而不是错误。

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

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

Avoid legacy date-time classes

你正在使用几年前由现代java.time类取代的糟糕的日期时间类。

Daylight Saving 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不代表片刻,不是时间轴上的一个点。因此,如果已知某个时区是针对该日期和时间,我们可以应用ZoneId来获取ZonedDateTime

在这个例子中,我们任意选择两个区域来应用,这样你就可以看到不同的结果。在美国,3月10日是DST跳跃的那一天。在法国这样的欧洲大部分地区,跳跃计划在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 [America / New_York]


About 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
投票

字符串"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不存在(在那个小时内也没有任何其他秒) 。

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


0
投票

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

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

相关文章