2016-06-26 7 views
7

Ich versuche, eine Mischung aus verschiedenen Code um Datetime-Management zu nur Java 8 java.time Namespace zu bereinigen. Im Moment habe ich ein kleines Problem mit dem Standard DateTimeFormatter für Instant. Der DateTimeFormatter.ISO_INSTANT Formatierer zeigt nur Millisekunden, wenn sie nicht gleich Null sind.java.time.DateTimeFormatter: Benötigen ISO_INSTANT, die immer Millisekunden

Die Epoche wird als 1970-01-01T00:00:00Z anstelle von 1970-01-01T00:00:00.000Z gerendert.

Ich machte einen Komponententest, um das Problem zu erklären und wie wir die endgültigen Daten miteinander vergleichen müssen.

@Test 
public void java8Date() { 
    DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; 
    String epoch, almostEpoch, afterEpoch; 

    { // before epoch 
     java.time.Instant instant = java.time.Instant.ofEpochMilli(-1); 
     almostEpoch = formatter.format(instant); 
     assertEquals("1969-12-31T23:59:59.999Z", almostEpoch); 
    } 

    { // epoch 
     java.time.Instant instant = java.time.Instant.ofEpochMilli(0); 
     epoch = formatter.format(instant); 
     // This fails, I get 1970-01-01T00:00:00Z instead 
     assertEquals("1970-01-01T00:00:00.000Z", epoch); 
    } 

    { // after epoch 
     java.time.Instant instant = java.time.Instant.ofEpochMilli(1); 
     afterEpoch = formatter.format(instant); 
     assertEquals("1970-01-01T00:00:00.001Z", afterEpoch); 
    } 

    // The end game is to make sure this rule is respected (this is how we order things in dynamo): 
    assertTrue(epoch.compareTo(almostEpoch) > 0); 
    assertTrue(afterEpoch.compareTo(epoch) > 0); // <-- This assert would also fail if the second assert fails 

    { // to confirm we're not showing nanos 
     assertEquals("1970-01-01T00:00:00.000Z", formatter.format(Instant.EPOCH.plusNanos(1))); 
     assertEquals("1970-01-01T00:00:00.001Z", formatter.format(Instant.EPOCH.plusNanos(1000000))); 
    } 
} 
+3

Das Standardformat wird auch nur Nanosekunden anzeigen, wenn sie von Null abweichen. Wenn Sie immer Millisekunden (und niemals Nanosekunden) möchten, verwenden Sie einfach einen benutzerdefinierten Formatierer wie 'DateTimeFormatter formatter = DateTimeFormatter.ofPattern (" yyyy-MM-dd'T'HH: mm: ss.SSSX "). WithZone (ZoneId .of ("UTC")); '? – mihi

+0

Ich wollte so nah wie möglich an den Formatierer für 'Instant :: toString()' bleiben. Vielleicht hätte ich einfach ein Saitenmuster verwenden sollen. – Florent

Antwort

7

OK, schaute ich auf die der Quellcode und es ist ziemlich einfach:

DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendInstant(3).toFormatter(); 

Ich hoffe, dass es für alle Szenarien funktioniert, und es kann jemand anders helfen. Zögere nicht, eine bessere/sauberere Antwort hinzuzufügen.

einfach zu erklären, wo es aus, in the JDK's code kommt,

ISO_INSTANT wie folgt definiert ist:

public static final DateTimeFormatter ISO_INSTANT; 
static { 
    ISO_INSTANT = new DateTimeFormatterBuilder() 
      .parseCaseInsensitive() 
      .appendInstant() 
      .toFormatter(ResolverStyle.STRICT, null); 
} 

Und DateTimeFormatterBuilder::appendInstant deklariert als:

public DateTimeFormatterBuilder appendInstant() { 
    appendInternal(new InstantPrinterParser(-2)); 
    return this; 
} 

Und der Konstruktor InstantPrinterParser Signatur :

InstantPrinterParser(int fractionalDigits) 
+1

Wäre schön, wenn Sie mit dem untersuchten Quellcode verlinkt wären. –

+0

Also, wie können wir dies ändern, nur ms und nicht Nano – user1172490

+0

@BasilBourque Ich habe den Verweis auf Quellcode – Florent

0

Die accepted Answer by Florent ist korrekt und gut.

Ich möchte nur etwas Klarstellung hinzufügen.

Der erwähnte Formatierer DateTimeFormatter.ISO_INSTANT ist standardmäßig nur für die Klasse Instant. Andere Klassen wie OffsetDateTime und ZonedDateTime können standardmäßig andere Formatierer verwenden.

Die Klassen java.time bieten eine Auflösung bis zu nanosecond, viel feinere Granularität als milliseconds. Das bedeutet bis zu 9 Ziffern im Dezimalbruch und nicht nur 3 Ziffern.

Das Verhalten von DateTimeFormatter.ISO_INSTANT variiert um die Anzahl der Ziffern im Dezimalbruch. Wie der Doc sagt (Hervorhebung von mir):

Bei der Formatierung wird immer die Sekunde-Minute ausgegeben. Der Sekundenbereich gibt null, drei, sechs oder neun Ziffern aus wie erforderlich.

So auf den Datenwert innerhalb des Instant Objekt enthalten je, können Sie jeder dieser Ausgänge finden Sie unter:

2011-12-03T10: 15: 30Z

2011-12-03T10 : 15: 30.100Z

2011-12-03T10: 15: 30.

120Z

2011-12-03T10: 15: 30.123Z

2011-12-03T10: 15: 30.123400Z

2011-12-03T10: 15: 30.123456Z

2011-12 -03T10: 15: 30.123456780Z

2011-12-03T10: 15: 30.123456789Z

die Instant Klasse soll das sein Grundbaustein von java.time. Verwenden Sie es häufig für Datenübergabe, Datenspeicherung und Datenaustausch. Verwenden Sie zum Generieren von String-Darstellungen der Daten für die Präsentation für Benutzer OffsetDateTime oder ZonedDateTime.