简体   繁体   English

将字符串解析为日期的异常

[英]Exception parsing string to Date

I cannot see why this code is failing:我看不出为什么这段代码失败了:

@Test
public void test() {
    final SimpleDateFormat sdf= new SimpleDateFormat("yyyyMMddHHmm");
    try {
        sdf.setLenient(false);
        Date d = sdf.parse("202003290230");
    } catch (ParseException e){
        e.printStackTrace();
    }
}

I get the exception java.text.ParseException: Unparseable date .我收到异常java.text.ParseException: Unparseable date

If I set sdf.setLenient(true) then it works, but the time in the object Date returned is '03:30' and not '02:30'.如果我设置sdf.setLenient(true)那么它可以工作,但是 object 返回日期中的时间是“03:30”而不是“02:30”。

Can someone explain me what's going on in here?有人可以解释一下这里发生了什么吗? Thanks.谢谢。

As OH GOD SPIDERS noted in a comment your real problem is that that time doesn't exist in you default time zone because of the spring forward , the transition to summer time (DST).正如 OH GOD SPIDERS 在评论中指出的那样,您真正的问题是,由于spring forward (过渡到夏令时(DST)),您的默认时区中不存在该时间。

java.time java.time

I recommend that you use java.time, the modern Java date and time API, for your date and time work.我建议您使用 java.time,现代 Java 日期和时间 API,用于您的日期和时间工作。 The short-sighted answer is: use LocalDateTime from java.time.短视的答案是:使用 java.time 中的LocalDateTime

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmm");
    String dateTimeString = "202003290230";
    LocalDateTime ldt = LocalDateTime.parse(dateTimeString, formatter);
    System.out.println(ldt);

Output is: Output 是:

2020-03-29T02:30 2020-03-29T02:30

A LocalDateTime is a date and time without time zone. LocalDateTime是没有时区的日期和时间。 So it doesn't discover that the time doesn't exist in your time zone.因此,它不会发现您的时区中不存在时间。 The result is 2:30 as in the string.结果是字符串中的 2:30。

Detecting a non-existing time检测不存在的时间

It seems you're in a Central European time zone or some other time zone where summer time began on the last Sunday in March, and the clocks were turned forward from 2 to 3 (AM).您似乎处于中欧时区或其他时区,夏季时间从 3 月的最后一个星期日开始,时钟从 2 点(上午)调快到 3 点。 So there was no 2:30.所以没有2:30。 Supposing that you want to know, you may do:假设你想知道,你可以这样做:

    ZoneId zone = ZoneId.of("Europe/Paris");
    ZonedDateTime zdt = ldt.atZone(zone);
    if (zdt.toLocalDateTime().equals(ldt)) {
        System.out.println("The time " + zdt + " exists");
    } else {
        System.out.println("The time " + ldt + " does not exist in " + zone);
    }

The time 2020-03-29T02:30 does not exist in Europe/Paris欧洲/巴黎不存在时间 2020-03-29T02:30

java.time too gives you 3:30 instead of 2:30 when given a time in the spring gap. java.time 在 spring 间隙中给定时间时也会给您 3:30 而不是 2:30。 So when converting back from ZonedDateTime to LocalDateTime in this case we don't get the same time again, which we use for detecting the non-existing time.因此,在这种情况下,当从ZonedDateTime转换回LocalDateTime时,我们不会再得到相同的时间,我们用它来检测不存在的时间。

I further recommend that you use ZonedDateTime for past dates and times, not LocalDateTime .我进一步建议您将ZonedDateTime用于过去的日期和时间,而不是LocalDateTime

Java 6? Java 6?

This project is made with Java6 and the company doesn't want to update it, …这个项目是用 Java6 做的,公司不想更新它,…

java.time has been backported, and I have tested the code above with the backport, ThreeTen Backport, see the link at the bottom. java.time 已经被反向移植,我已经用反向移植,ThreeTen Backport 测试了上面的代码,见底部的链接。

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.在 Java 8 及更高版本以及更新的 Android 设备(来自 API 级别 26)中,现代 ZDB9734A 内置23871083ACE16。
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310).在非 Android Java 6 和 7 中获得 ThreeTen Backport,现代类的后向端口(JSR 310 的 ThreeTen)。 I'm unsure whether the very latest release of ThreeTen Backport works with Java 6 or only with Java 7(+).我不确定最新版本的 ThreeTen Backport 是否适用于 Java 6 或仅适用于 Java 7(+)。 If this is an issue, go back a few releases and find one that works with Java 6 too.如果这是一个问题,go 会返回几个版本并找到一个也适用于 Java 6 的版本。
  • On older Android either use desugaring or the Android edition of ThreeTen Backport.在较旧的 Android 上,要么使用去糖,要么使用 ThreeTen Backport 的 Android 版本。 It's called ThreeTenABP.它被称为 ThreeTenABP。 In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.在后一种情况下,请确保从带有子包的org.threeten.bp导入日期和时间类。

Don't use SimpleDateFormat不要使用 SimpleDateFormat

The date and time classes you were trying to use, Date and SimpleDateFormat , are poorly designed and long outdated.您尝试使用的日期和时间类DateSimpleDateFormat设计不佳且早已过时。 In your case they showed a behaviour that depends on a time zone that isn't present in the code at all, which is quite confusing.在您的情况下,他们表现出的行为取决于代码中根本不存在的时区,这非常令人困惑。 I recommend that you don't use those classes.我建议您不要使用这些类。

Links链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM