2016-11-21 2 views
7

Ich kann nicht herausfinden, wie man das DateTime-Parsing von Java8 so verhält, wie das Joda-Äquivalent, das ich zu ersetzen versuche. Das Problem ist, dass Jodas ISODateTimeFormat.dateTimeParser(); mir erlaubte, so wenig wie YYYY einzugeben, und es würde immer noch funktionieren (2016 würde zum Beispiel 2016-01-01T00: 00: 00.000Z "werden.) Wie kann ich dasselbe Verhalten von Java8 bekommen?Java8 entspricht Jodas ISODateTimeFormat.dateTimeParser()?

genug

der Code ist einfach ...

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(); 
     } 
    } 
    } 
} 

die Ergebnisse der Herausforderung ...

$ 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) 

Wie kann ich von diesen java.time.format.DateTimeParseException s aus dem „Java8 nicht loswerden kann? "Fälle?

Antwort

3

Dank @Tunaki für die vorgeschlagene alternative Syntax. Dies wird Ihnen helfen, Ihre eingegebenen Werte zu parsen. Dementsprechend anpassen.

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(); 

Testfall: (-06: 00 Offset)

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(); 
     } 
    } 
} 

Ausgang: (-06: 00 Offset)

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 
+2

Dies wäre sauberer mit der '[...]' Syntax für optionale Teile. Es sieht aus wie 'JJJJ-MM-TT [' T'HH [: mm [: ss]]] [. SSSVV] ' – Tunaki

+0

Hmmm. '' 'java.time.format.DateTimeParseException: Text '2016-11-21' konnte nicht beim Index 10''' geparst werden, wenn ich versuche," 2016-11-21 "durch diesen zu senden. Ich nehme das DateTimeFormatter, das aus diesem Erbauer kommt und gebe es nur '' 'OffsetDateTime.parse (Kandidat, dtFmt);' '', nein? –

+2

Ich lief genau so, wie du es erwähnt hast. Es funktioniert hier gut. Der Testfall wurde zur Antwort hinzugefügt. – Veeram

2

Dies wird alle Ihre Daten mit Ausnahme der etwas funky 2016-11-21T01 analysieren. Wenn Sie wirklich brauchen, haben Sie einen Blick auf die Art und Weise DateTimeFormatterBuilder ist der ISO_TIME Formatierer. Es verwendet ein optionales Sekundenfeld. Kopiere es und mache das Minutenfeld optional.

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

DateTimeFormatter ist Ihre Klasse. Es erfordert jedoch einige Gewöhnung an dieses neue Paket java.time. Ich habe damit gearbeitet und nach einer Weile fand ich es sehr flexibel und kraftvoll. Ich habe einen kleinen Artikel geschrieben, in dem ich eine allgemeine Idee beschrieben habe, wie man versucht, einen String unbekannten Formats zu einem Date zu analysieren. Hier ist der Link: Java 8 java.time package: parsing any string to date

+2

"' '' DateTimeFormatter''' ... ist etwas gewöhnungsbedürftig ... "es wurden keine richtigen Wörter gesprochen. Der DateTimeFormatter ist der Schlüssel. –