Warum fehlt in den Java 8 java.time-Klassen eine getMillis () -Methode?

64

Java 8 hat eine völlig neue Bibliothek für Datums- und Uhrzeitangaben im Paket java.time, die für alle sehr willkommen ist, die JodaTime zuvor verwenden mussten oder Probleme damit hatten, eigene Hilfsmethoden für die Datumsverarbeitung zu erstellen. Viele Klassen in diesem Paket stellen Zeitstempel dar und haben Hilfsmethoden getHour(), um Stunden vom Zeitstempel, getMinute()Minuten vom Zeitstempel, getNano()Nanometer vom Zeitstempel usw. zu erhalten.

Mir ist aufgefallen, dass sie keine Methode haben getMillis(), um die Millis des Zeitstempels zu ermitteln. Stattdessen müsste man method aufrufen get(ChronoField.MILLI_OF_SECOND). Für mich scheint es eine Inkonsistenz in der Bibliothek zu sein. Weiß jemand, warum eine solche Methode fehlt oder wie Java 8 noch in der Entwicklung ist, besteht die Möglichkeit, dass es später hinzugefügt wird?

https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html

Die hier definierten Klassen repräsentieren die wichtigsten Datum-Uhrzeit-Konzepte, einschließlich Zeitpunkte, Dauer, Datum, Uhrzeit, Zeitzone und Zeiträume. Sie basieren auf dem ISO-Kalendersystem, dem De-facto -Weltkalender nach den proleptischen gregorianischen Regeln. Alle Klassen sind unveränderlich und threadsicher.

Jede Datums- und Uhrzeitinstanz besteht aus Feldern, die von den APIs bequem zur Verfügung gestellt werden. Informationen zum Zugriff auf die Felder auf niedrigerer Ebene finden Sie im java.time.temporalPaket. Jede Klasse enthält Unterstützung für das Drucken und Parsen aller Arten von Datums- und Uhrzeitangaben. java.time.formatAnpassungsoptionen finden Sie im Paket ...

Beispiel für diese Art von Klasse:
https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html

Eine Datums- und Uhrzeitangabe ohne Zeitzone im ISO-8601-Kalendersystem, z. B. 2007-12-03T10: 15: 30.

LocalDateTimeist ein unveränderliches Datum / Uhrzeit-Objekt, das eine Datum / Uhrzeit darstellt und häufig als Jahr / Monat / Tag / Stunde / Minute / Sekunde angesehen wird. Auf andere Felder für Datum und Uhrzeit, z. B. Tag des Jahres, Wochentag und Woche des Jahres, kann ebenfalls zugegriffen werden. Die Zeit wird auf Nanosekunden genau dargestellt. Beispielsweise kann der Wert "2. Oktober 2007 um 13: 45.30.123456789" in einem LocalDateTime...

Tarmo
quelle
Scheint, als wollten sie mithilfe des Polymorphismus eine Reihe von Methoden auflösen, die alle aufgerufen wurden get(), anstatt ihnen individuelle, eindeutige Namen zu geben. Wenn es Sie stört, schreiben Sie eine Klasse, die die ursprüngliche Klasse erbt, und fügen Sie Ihre eigene getMillis()Methode in die neue Klasse ein.
Robert Harvey
@RobertHarvey Die meisten Klassen im Paket java.time sind unveränderlich und können nicht erweitert werden.
Assylias
2
@RobertHarvey Die Frage für mich ist nicht, wie ich das lösen kann. Es war nur eine seltsame Inkonsistenz, und ich fragte mich, ob es dafür eine interessante Erklärung gibt.
Tarmo
Ich habe die Idee, dass einige Architekturen / Betriebssysteme Millisekunden nicht zuverlässig unterstützen. Mit anderen Worten, die Systemzeit kann nicht auf die Millisekunde, sondern nur auf die Zenti- oder Entscheidungssekunde bezogen werden.
Marco
Unter stackoverflow.com/a/23945792/40064 erfahren Sie , wie Sie dies über die InstantKlasse tun können
Wim Deblauwe,

Antworten:

63

JSR-310 basiert auf Nanosekunden und nicht auf Millisekunden. Als solche basieren die kleinsten sinnvollen Methoden auf Stunden, Minuten, Sekunden und Nanosekunden. Die Entscheidung, eine Nanosekundenbasis zu haben, war eine der ursprünglichen Entscheidungen des Projekts und eine, die ich nachdrücklich für richtig halte.

Das Hinzufügen einer Methode für Millis würde die von Nanosekunden überlappen, was nicht naheliegend ist. Benutzer müssten sich überlegen, ob das Nano-Feld beispielsweise Nano-of-Second oder Nano-of-Milli ist. Das Hinzufügen einer verwirrenden zusätzlichen Methode ist nicht wünschenswert, daher wurde die Methode weggelassen. Wie bereits erwähnt, ist die Alternative get(MILLI_OF_SECOND)verfügbar.

FWIW, ich würde es ablehnen, die getMillis()Methode in Zukunft hinzuzufügen .

JodaStephen
quelle
1
Ich habe einige sehr gute Antworten auf diese Frage erhalten, aber Ihre Antwort ist meine Lieblingsantwort, da sie kurz ist und dennoch einen sehr guten Punkt ergibt und mich wirklich von der Notwendigkeit dieses Ansatzes überzeugt. Danke.
Tarmo
12
@ s3ib Wenn Sie das Profil des Antwortenden überprüfen , werden Sie auch feststellen, dass er ein Spezifikationsvorsprung für genau die API ist, nach der Sie fragen. Dies macht eine Antwort so
Mücke
Es instant.getEpochSecond * 1000 + instant.getNano / 1000000ist also vernünftig , etwas zu tun , um mit älteren Java-APIs, Javascript usw. (an dieser Stelle alle) kommunizieren zu können.
Nilskp
10
nein, in diesem Fall können Sie nur instant.toEpochMilli () verwenden , download.java.net/jdk8/docs/api/java/time/...
JodaStephen
20

Vor seiner Zeit bei openJDK war threeten bei github und davor bei sourceforge. Damals hat Stephen Colebourne, der für jsr-310 verantwortlich ist, eine Umfrage durchgeführt, die Sie immer noch auf der SourceForge-Site finden können .

The fourth question on the survey covered the method names for LocalTime:
1) getHourOfDay(), getMinuteOfHour(), getSecondOfMinute(), getNanoOfSecond()
2) getHour(), getMinute(), getSecond(), getNanoOfSecond()
3) getHour(), getMinute(), getSecond(), getNano()
4) another idea

Nur 6,23% wählten die Antwort Nr. 4 und etwa 15% fragten nach a getMillis(), dh weniger als 1% der Gesamtstimmen.

Das ist wahrscheinlich der Grund, warum es überhaupt keine gab getMillisund ich auf der openjdk-Mailingliste nichts gefunden habe, so dass die Angelegenheit anscheinend danach nicht besprochen wurde.

Assylias
quelle
3
Ich denke, dass es wahrscheinlicher ist, dass Menschen mehrere Entscheidungen treffen, wenn sie eine dieser Entscheidungen treffen, auch wenn ihre ideale Wahl unter "andere" steht. Ich könnte mich jedoch irren.
Allon Guralnek
2
@AllonGuralnek Ja, definitiv - jedoch war die Millisekunden-Komponente in der Datums-API wichtig, da seit der Epoche alles auf einer Anzahl von Millis basiert. In der neuen API ist es IMO weniger relevant. In den meisten Anwendungsfällen benötigen Sie entweder eine zweite Genauigkeit oder die beste verfügbare Genauigkeit (Nanometer). Ich kann mich irren.
Assylias
1
Dies scheint nach der Benennung von Methoden zu fragen , nicht nach den Methoden, die existieren sollten.
Svick
1
Richtig, sorry, mir war nicht klar: Ich meinte die Frage aus der Umfrage, die nicht direkt mit dieser Frage zusammenhängt.
Svick
15

Die Klassen, die eindeutige UTC-Zeiten darstellen (dies sind Instant, OffsetDateTime, ZonedDateTime), haben zwei Hilfsmethoden für den Zugriff auf den absoluten Offset aus der Java-Epoche, dh die sogenannte Millisekundenzeit in der java.util.Date, die Sie verwenden können auf Millisekunden zu bekommen

long getEpochSecond()
int getNano()

1000L*getEpochSecond() + getNano() / 1000000L;

Einige Gründe, warum dies gewählt wurde, long getEpochMillis()wurden in der Mailingliste jsr 310 besprochen , von denen ich einige aus praktischen Gründen extrahiert habe:

Es erscheint vernünftig anzunehmen, dass die Millisekundengenauigkeit nicht ausreicht. Eine Genauigkeit von mehr als einer Nanosekunde scheint jedoch zu hoch zu sein

...

Um dies zu implementieren, wäre meine bevorzugte Option 64 Bit lange Sekunden (mit Vorzeichen) + 32 Bit in Nanosekunden (ohne Vorzeichen).

...

Ich bevorzuge die Aufteilung auf die zweite Ebene, da dies die offizielle SI-Zeiteinheit in der Wissenschaft und der allgemeinste Standard ist.

Das Teilen auf Tagesebene ist für Augenblicke problematisch, da es keine Schaltsekunden handhabt. Das Aufteilen auf der Millisekunden-Ebene, während es sich etwas besser in den Rest von Java integriert, scheint wirklich seltsam. Außerdem verliert es im unterstützten Bereich.

Das Aufteilen in der vorgeschlagenen Sekunde ergibt eine Reihe von Momenten von Nanosekunden über 290 Milliarden Jahre. Obwohl niemand diese Präzision jemals über diesen Zeitraum hinweg anwenden sollte, würde ich vorschlagen, dass es einfacher ist, sie zu unterstützen, als sie zu blockieren. Das Aufteilen auf Tagesebene ist für Augenblicke problematisch, da es keine Schaltsekunden handhabt

Ich habe das Gefühl, dass ein weiterer Grund darin bestand, die Konvertierung von java.util.Date in JSR310-Klassen absichtlich zu erschweren, in der Hoffnung, dass Entwickler versuchen würden, die Unterschiede zwischen den verschiedenen Optionen zu verstehen und die neuen Klassen nicht nur blind (falsch) zu verwenden.

Warum die LocalDateTimeKlasse diese Methoden nicht hat - sie können dort möglicherweise nicht existieren, weil sie LocalDateTimenicht an die UTC-Zeitachse gebunden sind, bis Sie entscheiden, in welcher Zone Sie sich befinden oder wie hoch Ihr UTC-Offset ist OffsetDateTimeoder ZonedDateTime(beide haben die benötigten Methoden).

Alternativ können Sie eine eigene LOCAL_EPOCHKonstante für definieren 1970-01-01T00:00:00und dann a ausführen MILLIS.between(LOCAL_EPOCH, localTime), um eine Dauer in Millisekunden zu erhalten. Dieser Wert ist jedoch nicht kompatibel mit Werten, die von System.currentTimeMilliseconds()oder zurückgegeben werden java.util.Date.getTime(), es sei denn, Sie definieren Ihre Ortszeit als UTC-Zeit. In diesem Fall können Sie jedoch auch Instant direkt oder OffsetDateTime mit ZoneOffset.UTC verwenden.

mkadunc
quelle
4
" Sie können dort möglicherweise nicht existieren, weil LocalDateTime nicht an die UTC-Zeitachse gebunden ist " => Eine LocalDateTime könnte mit Sicherheit eine getMillisMethode haben, die im Grunde genommen zurückgibt getNanos()/1e6- die Tatsache, dass es kein Augenblick ist, verhindert nicht, dass es eine Millisekunde hat Komponente.
Assylias
2
" Ich habe das Gefühl, dass ein weiterer Grund darin bestand, die Konvertierung von java.util.Date zu JSR310-Klassen absichtlich zu erschweren. " Wahrscheinlich wahr, aber leider ist "millis since epoch" eine fast universelle Darstellung der Zeit, also für alles, was benötigt wird Für die Kommunikation mit älteren Java-APIs, Javascript und allem anderen ist diese Auslassung ein echtes Problem.
Nilskp
Ihr Code-Snippet oben ist falsch - Sie müssen die getEpochSecond mit 1000 multiplizieren.
Tin Man
@ Nilskp Sie sind zwei verschiedene Dinge. Die Frage ist ungefähr so getMillis()wie in getMillis-of-second; du sprichst von "millis since epoch". Ersteres fehlt, wie in der akzeptierten Antwort erläutert. Letzteres gibt es bereits als Instant.toEpochMillis(). Also, für eine LocalDateTime, würden Sie gehen:ldt.toInstant(offset).toEpochMillis()
SusanW