【问题标题】:Java8 equivalent of Joda's ISODateTimeFormat.dateTimeParser()?Java8 相当于 Joda 的 ISODateTimeFormat.dateTimeParser()?
【发布时间】:2016-11-23 04:38:05
【问题描述】:

我不知道如何让 Java8 的 DateTime 解析表现得像我试图替换的 Joda 等价物。问题是 Joda 的 ISODateTimeFormat.dateTimeParser(); 允许我输入 YYYY 并且它仍然可以工作(例如,2016 年将变为 2016-01-01T00:00:00.000Z")。我怎样才能从 Java8 获得同样的行为?

代码很简单……

import java.time.OffsetDateTime;
import java.time.temporal.ChronoField;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

public class Java8OffsetDateTime {
  public static void main(String[] args) {
    String[] candidates =
        { "2016-11-21T17:54:51.841Z",
            "2016-11-21T09:54:51.841-08:00",
            "2016", // Java8 no can do?
            "2016-11", // Java8 no can do?
            "2016-11-21", // Java8 no can do?
            "2016-11-21T01", // Java8 no can do?
            "2016-11-21T01:02", // Java8 no can do?
            "2016-11-21T01:02:03" // Java8 no can do?
        };
    DateTimeFormatter JodaDateTimeFormatter = ISODateTimeFormat.dateTimeParser();
    for (String candidate : candidates) {
      System.out.println("\ncandidate:\t\"" + candidate + "\"");
      DateTime jodaDateTime = JodaDateTimeFormatter.parseDateTime(candidate);
      System.out.println("Joda:\t" + jodaDateTime);
      try {
        OffsetDateTime java8OffsetDateTime = OffsetDateTime.parse(candidate);
        System.out.println("Java8:\t" + java8OffsetDateTime);
        long jodaMillis = jodaDateTime.getMillis();
        long javaMillis = java8OffsetDateTime.toInstant().toEpochMilli();
        System.out.printf("jodaMillis:%d %s javaMillis:%d\n",
            jodaMillis,
            (jodaMillis==javaMillis) ? "==" : "!=",
            javaMillis);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}

结果就是挑战……

$ java -cp ~/work/joda-time-2.9.6/joda-time-2.9.6.jar:. Java8OffsetDateTime

candidate:  "2016-11-21T17:54:51.841Z"
Joda:   2016-11-21T09:54:51.841-08:00
Java8:  2016-11-21T17:54:51.841Z
jodaMillis:1479750891841 == javaMillis:1479750891841

candidate:  "2016-11-21T09:54:51.841-08:00"
Joda:   2016-11-21T09:54:51.841-08:00
Java8:  2016-11-21T09:54:51.841-08:00
jodaMillis:1479750891841 == javaMillis:1479750891841

candidate:  "2016"
Joda:   2016-01-01T00:00:00.000-08:00
java.time.format.DateTimeParseException: Text '2016' could not be parsed at index 4
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:387)
    at Java8OffsetDateTime.main(Java8OffsetDateTime.java:26)

candidate:  "2016-11"
Joda:   2016-11-01T00:00:00.000-07:00
java.time.format.DateTimeParseException: Text '2016-11' could not be parsed at index 7
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:387)
    at Java8OffsetDateTime.main(Java8OffsetDateTime.java:26)

candidate:  "2016-11-21"
Joda:   2016-11-21T00:00:00.000-08:00
java.time.format.DateTimeParseException: Text '2016-11-21' could not be parsed at index 10
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:387)
    at Java8OffsetDateTime.main(Java8OffsetDateTime.java:26)

candidate:  "2016-11-21T01"
Joda:   2016-11-21T01:00:00.000-08:00
java.time.format.DateTimeParseException: Text '2016-11-21T01' could not be parsed at index 13
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:387)
    at Java8OffsetDateTime.main(Java8OffsetDateTime.java:26)

candidate:  "2016-11-21T01:02"
Joda:   2016-11-21T01:02:00.000-08:00
java.time.format.DateTimeParseException: Text '2016-11-21T01:02' could not be parsed at index 16
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:387)
    at Java8OffsetDateTime.main(Java8OffsetDateTime.java:26)

candidate:  "2016-11-21T01:02:03"
Joda:   2016-11-21T01:02:03.000-08:00
java.time.format.DateTimeParseException: Text '2016-11-21T01:02:03' could not be parsed at index 19
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:387)
    at Java8OffsetDateTime.main(Java8OffsetDateTime.java:26)

如何从“Java8 不能做”中摆脱那些java.time.format.DateTimeParseExceptions?案例?

【问题讨论】:

    标签: java java-8 jodatime


    【解决方案1】:

    感谢@Tunaki 提出替代语法的建议。这将帮助您解析您提供的输入值。相应调整。

    OffsetDateTime java8OffsetDateTime = OffsetDateTime.parse(candidate, offsetDateTimeFormatter );
    
    DateTimeFormatter customOffsetDateTimeFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy[-MM][-dd['T'HH[:mm[:ss]]]][.SSSXXX]")
                .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
                .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
                .parseDefaulting(ChronoField.OFFSET_SECONDS, ZoneOffset.of("-08:00").getTotalSeconds())
                .toFormatter();
    

    测试用例:(-06:00 偏移)

    import java.time.OffsetDateTime;
    import java.time.format.DateTimeFormatter;
    import java.time.format.DateTimeFormatterBuilder;
    import java.time.temporal.ChronoField;
    public class App 
     {
        public static void main(String[] args) {
            String[] candidates =
                {"2016-11-21T15:54:51.841Z",
                     "2016-11-21T09:54:51.841-06:00",
                        "2016", // Java8 no can do?
                        "2016-11", // Java8 no can do?
                        "2016-11-21", // Java8 no can do?
                        "2016-11-21T01", // Java8 no can do?
                        "2016-11-21T01:02", // Java8 no can do?
                        "2016-11-21T01:02:03" // Java8 no can do?*/
                };
    
            DateTimeFormatter customOffsetDateTimeFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy[-MM][-dd['T'HH[:mm[:ss]]]][.SSSXXX]")
                .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
                .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
                .parseDefaulting(ChronoField.OFFSET_SECONDS, ZoneOffset.of("-06:00").getTotalSeconds())
                .toFormatter();
    
        org.joda.time.format.DateTimeFormatter jodaDateTimeFormatter = ISODateTimeFormat.dateTimeParser();
        for (String candidate : candidates) {
            System.out.println("\ncandidate:\t\"" + candidate + "\"");
            DateTime jodaDateTime = jodaDateTimeFormatter.parseDateTime(candidate);
            System.out.println("Joda:\t" + jodaDateTime);
            try {
                OffsetDateTime java8OffsetDateTime = OffsetDateTime.parse(candidate,customOffsetDateTimeFormatter);
                System.out.println("Java8:\t" + java8OffsetDateTime);
                long jodaMillis = jodaDateTime.getMillis();
                long javaMillis = java8OffsetDateTime.toInstant().toEpochMilli();
                System.out.printf("jodaMillis:%d %s javaMillis:%d\n",
                        jodaMillis,
                        (jodaMillis == javaMillis) ? "==" : "!=",
                        javaMillis);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }  
    

    输出:(-06:00 偏移)

        candidate:  "2016-11-21T15:54:51.841Z"
        Joda:   2016-11-21T09:54:51.841-06:00
        Java8:  2016-11-21T15:54:51.841Z
        jodaMillis:1479743691841 == javaMillis:1479743691841
    
        candidate:  "2016-11-21T09:54:51.841-06:00"
        Joda:   2016-11-21T09:54:51.841-06:00
        Java8:  2016-11-21T09:54:51.841-06:00
        jodaMillis:1479743691841 == javaMillis:1479743691841
    
        candidate:  "2016"
        Joda:   2016-01-01T00:00:00.000-06:00
        Java8:  2016-01-01T00:00-06:00
        jodaMillis:1451628000000 == javaMillis:1451628000000
    
        candidate:  "2016-11"
        Joda:   2016-11-01T00:00:00.000-05:00
        Java8:  2016-11-01T00:00-06:00
        jodaMillis:1477976400000 != javaMillis:1477980000000
    
        candidate:  "2016-11-21"
        Joda:   2016-11-21T00:00:00.000-06:00
        Java8:  2016-11-21T00:00-06:00
        jodaMillis:1479708000000 == javaMillis:1479708000000
    
        candidate:  "2016-11-21T01"
        Joda:   2016-11-21T01:00:00.000-06:00
        Java8:  2016-11-21T01:00-06:00
        jodaMillis:1479711600000 == javaMillis:1479711600000
    
        candidate:  "2016-11-21T01:02"
        Joda:   2016-11-21T01:02:00.000-06:00
        Java8:  2016-11-21T01:02-06:00
        jodaMillis:1479711720000 == javaMillis:1479711720000
    
        candidate:  "2016-11-21T01:02:03"
        Joda:   2016-11-21T01:02:03.000-06:00
        Java8:  2016-11-21T01:02:03-06:00
        jodaMillis:1479711723000 == javaMillis:1479711723000
    

    【讨论】:

    • 对可选部分使用[...] 语法会更简洁。看起来像yyyy-MM-dd['T'HH[:mm[:ss]]][.SSSVV]
    • 嗯。 java.time.format.DateTimeParseException: Text '2016-11-21' could not be parsed at index 10 当我尝试通过它发送“2016-11-21”时。我从这个构建器中取出 DateTimeFormatter,然后把它交给OffsetDateTime.parse(candidate, dtFmt);,不是吗?
    • 我跑的方式和你说的一模一样。它在这里工作正常。将测试用例添加回答案。
    • @Veeram 是的......我做错了什么。即便如此,如果没有 Java8 中的大后空翻,我的用例似乎确实不受支持。谢谢回复。我要再玩一些。也许乔达一开始就“帮助”我太多了
    • @Veeram 你的 DateTimeFormatterBuilder 真的很接近,但是对于通过的候选人,Java8 毫秒不匹配除了第一个候选人之外的任何人的乔达毫秒(问题已被重组以显示这一点)。如果我能弄清楚为什么您的格式构建器在此案中挣扎...candidate: "2016-11-21T09:54:51.841-08:00" Joda: 2016-11-21T09:54:51.841-08:00 Java8: 2016-11-21T09:54:51.841Z jodaMillis:1479750891841 != javaMillis:1479722091841 我想我们赢了!
    【解决方案2】:

    这将解析您的所有日期,除了有点时髦的 2016-11-21T01。如果您真的需要查看DateTimeFormatterBuilder 构建ISO_TIME 格式化程序的方式。它使用可选的秒字段。复制它并使分钟字段也可选。

    DateTimeFormatter isoDateParser = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .optionalStart()
            .appendLiteral('T')
            .append(DateTimeFormatter.ISO_TIME)
            .toFormatter();
    

    【讨论】:

      【解决方案3】:

      DateTimeFormatter 是你的班级。但是,需要一些时间来适应这个新的 java.time 包。我使用它,一段时间后我发现它非常灵活和强大。我写了一篇小文章,描述了如何尝试将未知格式的字符串解析为日期的一般想法。这是链接:Java 8 java.time package: parsing any string to date

      【讨论】:

      • "DateTimeFormatter...需要一些时间来适应..." 更真实的话还没说出来。 DateTimeFormatter 是关键。
      猜你喜欢
      • 1970-01-01
      • 2018-02-24
      • 1970-01-01
      • 2014-04-04
      • 2020-01-29
      • 2013-07-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多