Dlaczego w klasach Java 8 java.time brakuje metody getMillis ()?

64

Java 8 ma zupełnie nową bibliotekę dat i godzin w pakiecie java.time, co jest bardzo mile widziane dla każdego, kto musiał wcześniej używać JodaTime lub miał problemy z tworzeniem własnych metod pomocniczych przetwarzania daty. Wiele klas w tym pakiecie reprezentuje znaczniki czasu i mają metody pomocnicze, takie jak getHour()uzyskiwanie godzin od znacznika czasu, getMinute()uzyskiwanie minut od znacznika czasu, getNano()uzyskiwanie nanosów z znacznika czasu itp.

Zauważyłem, że nie mają metody wywołania getMillis()milisów znacznika czasu. Zamiast tego trzeba by wywołać metodę get(ChronoField.MILLI_OF_SECOND). Dla mnie to wydaje się niespójnością w bibliotece. Czy ktoś wie, dlaczego brakuje takiej metody lub skoro Java 8 jest wciąż w fazie rozwoju, czy istnieje możliwość, że zostanie ona dodana później?

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

Klasy zdefiniowane tutaj reprezentują podstawowe pojęcia data-czas, w tym momenty, czasy trwania, daty, godziny, strefy czasowe i okresy. Opierają się na systemie kalendarza ISO, który jest de facto kalendarzem światowym, opartym na proleptycznych zasadach gregoriańskich. Wszystkie klasy są niezmienne i bezpieczne dla wątków.

Każda instancja daty i godziny składa się z pól, które są dogodnie udostępniane przez interfejsy API. Aby uzyskać dostęp do pól na niższym poziomie, patrz java.time.temporalpakiet. Każda klasa obejmuje obsługę drukowania i analizowania wszystkich dat i godzin. Informacje na temat java.time.formatopcji dostosowywania znajdują się w pakiecie ...

Przykład tego rodzaju klasy:
https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html

Data i godzina bez strefy czasowej w systemie kalendarza ISO-8601, np. 2007-12-03T10: 15: 30.

LocalDateTimejest niezmiennym obiektem data-godzina, który reprezentuje datę-godzinę, często postrzeganą jako rok-miesiąc-dzień-godzina-minuta-sekunda. Można również uzyskać dostęp do innych pól daty i godziny, takich jak dzień roku, dzień tygodnia i tydzień roku. Czas jest reprezentowany z dokładnością do nanosekund. Na przykład wartość „2 października 2007 o 13: 45.30.123456789” można zapisać w LocalDateTime...

Tarmo
źródło
Wygląda na to, że chcieli użyć polimorfizmu do rozwiązania wielu wywoływanych metod get(), zamiast nadawać im indywidualne, unikalne nazwy. Jeśli ci to przeszkadza, napisz klasę, która dziedziczy klasę oryginalną, i umieść własną getMillis()metodę w nowej klasie.
Robert Harvey
@RobertHarvey Większość klas w pakiecie java.time jest niezmienna i nie można jej rozszerzyć.
assylias
2
@RobertHarvey Pytanie nie brzmi, jak mogę to rozwiązać. Po prostu wydawało się to dziwną niespójnością i zastanawiałem się, czy istnieje na to interesujące wyjaśnienie.
Tarmo
Mam pomysł, że niektóre architektury / systemy operacyjne nie obsługują niezawodnie milisekund. Innymi słowy, czasu systemowego nie można odczytać w milisekundach, a jedynie w centys lub decisecond.
Marco
Zobacz stackoverflow.com/a/23945792/40064, jak to zrobić za pośrednictwem Instantklasy
Wim Deblauwe

Odpowiedzi:

63

JSR-310 oparty jest na nanosekundach, a nie milisekundach. Jako taki, minimalny zestaw rozsądnych metod oparty jest na godzinie, minutach, sekundach i nanosekundach. Decyzja o ustanowieniu bazy nanosekundowej była jedną z pierwotnych decyzji projektu i zdecydowanie uważam ją za słuszną.

Dodanie metody dla milisów nakładałoby się na metodę nanosekundową, co jest nieoczywistym sposobem. Użytkownicy musieliby zastanowić się, czy na przykład nanotechnologia była nanosekundowa, czy nanomiliowa. Dodanie mylącej dodatkowej metody nie jest pożądane, więc metodę tę pominięto. Jak wskazano, alternatywa get(MILLI_OF_SECOND)jest dostępna.

FWIW, nie chciałbym dodawać tej getMillis()metody w przyszłości.

JodaStephen
źródło
1
Otrzymałem kilka bardzo dobrych odpowiedzi na to pytanie, ale twoja odpowiedź jest moją ulubioną, ponieważ jest krótka, a jednak nadal ma bardzo dobrą rację i naprawdę przekonuje mnie o konieczności takiego podejścia. Dziękuję Ci.
Tarmo
12
@ s3ib, jeśli sprawdzisz profil odpowiadającego , zauważysz również, że jest on liderem specyfikacji interfejsu API, o który pytasz. To sprawia, że ​​odpowiedź jest tak autorytatywna, jak to tylko możliwe, prawda :)
komara
Czy więc robienie tego instant.getEpochSecond * 1000 + instant.getNano / 1000000jest uzasadnione, aby móc komunikować się ze starszymi (w tym momencie wszystkimi) interfejsami API Java, JavaScript itp.?
nilskp
10
nie, w takim przypadku możesz po prostu użyć instant.toEpochMilli () download.java.net/jdk8/docs/api/java/time/…
JodaStephen
20

Przed byciem częścią openJDK, threeten był na githubie, a wcześniej na sourceforge. Wtedy Stephen Colebourne, który jest liderem specyfikacji na jsr-310, przeprowadził ankietę, którą wciąż można znaleźć na stronie sourceforge .

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

tylko 6,23% wybrało odpowiedź nr 4, a wśród nich około 15% poprosiło o getMillis(), tj. mniej niż 1% ogólnej liczby głosów.

Prawdopodobnie dlatego nie było go w ogóle getMillisi nie mogłem znaleźć niczego związanego z listą dyskusyjną openjdk, więc sprawa najwyraźniej nie była później omawiana.

assylias
źródło
3
Myślę, że dając ludziom kilka opcji, bardziej prawdopodobne jest, że wybiorą jedną z tych opcji, nawet jeśli ich idealny wybór jest pod „innym”. Mogę się jednak mylić.
Allon Guralnek
2
@AllonGuralnek Tak, zdecydowanie - jednak składnik milisekund był ważny w interfejsie API Data, ponieważ wszystko było oparte na liczbie milis od epoki. W nowym API jest mniej istotne IMO. W większości przypadków użycia potrzebna jest druga precyzja lub najlepsza dostępna precyzja (nanosy). Mogę się mylić.
assylias
1
To wydaje się pytać o nazewnictwo metod, a nie o to, które metody powinny istnieć.
sick
1
Racja, przepraszam, nie byłem jasny: miałem na myśli pytanie z ankiety, że nie ma ona bezpośredniego związku z tym pytaniem.
svick
15

Klasy reprezentujące jednoznaczne czasy UTC (są to Instant, OffsetDateTime, ZonedDateTime) mają dwie metody pomocnicze w celu uzyskania dostępu do bezwzględnego przesunięcia w stosunku do epoki Java, tj. To, co nazywamy „czasem milisekundowym” w java.util.Date, którego można użyć dostać się w milisekundach

long getEpochSecond()
int getNano()

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

Niektóre powody, dla których wybrano to zamiast, long getEpochMillis()zostały omówione na liście mailingowej jsr 310 , niektóre z nich wyodrębniłem dla wygody:

rozsądne wydaje się założenie, że precyzja milisekund nie będzie wystarczająca. Jednak wszystko, co jest większe niż precyzja nanosekundowa, wydaje się nadmierne

...

Aby to zaimplementować, moją preferowaną opcją byłoby 64-bitowe długie sekundy (podpisane) + 32-bitowe int nanosekundy (niepodpisane).

...

Wolę, aby podział był na drugim poziomie, ponieważ jest to oficjalna jednostka czasu SI w nauce i najbardziej powszechnie uzgodniony standard.

Dzielenie na poziomie dni jest dla instancji problematyczne, ponieważ nie obsługuje sekund przestępnych. Dzielenie na poziomie milisekund, przy nieco lepszej integracji z resztą Javy, wydaje się naprawdę dość dziwne. Plus traci w obsługiwanym zakresie.

Podział na drugi zgodnie z propozycją daje szereg momentów nanosekund w ciągu 290 miliardów lat. Chociaż nikt nigdy nie powinien używać tej precyzji w tym przedziale czasu, sugeruję, że łatwiej jest ją wesprzeć niż ją zablokować. Rozłupywanie na poziomie dni jest problematyczne dla chwil, ponieważ nie obsługuje sekund przestępnych

Mam wrażenie, że innym powodem było celowe utrudnienie konwersji z java.util.Date na klasy JSR310, mając nadzieję, że programiści spróbują zrozumieć różnice między poszczególnymi opcjami, a nie tylko ślepo (źle) użyją nowych klas.

Co do tego, dlaczego LocalDateTimeklasa nie ma tych metod - prawdopodobnie nie mogą tam istnieć, ponieważ LocalDateTimenie są powiązane z osią czasu UTC, dopóki nie zdecydujesz, w której strefie jesteś lub jakie jest przesunięcie UTC, w którym momencie masz OffsetDateTimelub ZonedDateTime(oba mają potrzebne metody).

Alternatywnie, możesz zdefiniować własną LOCAL_EPOCHstałą, 1970-01-01T00:00:00a następnie zrobić, MILLIS.between(LOCAL_EPOCH, localTime)aby uzyskać pewien czas trwania w milisekundach. Ta wartość nie będzie jednak zgodna z żadną wartością zwróconą przez System.currentTimeMilliseconds()lub java.util.Date.getTime(), chyba że zdefiniujesz czas lokalny jako czas UTC; ale w tym przypadku równie dobrze możesz użyć Instant bezpośrednio lub OffsetDateTime z ZoneOffset.UTC.

mkadunc
źródło
4
nie mogą tam istnieć, ponieważ LocalDateTime nie jest powiązany z osią czasu UTC ” => LocalDateTime z pewnością może mieć getMillismetodę, która w zasadzie powróciłaby getNanos()/1e6- fakt, że nie jest to chwila, nie uniemożliwia milisekundy składnik.
assylias
2
Mam wrażenie, że innym powodem było celowe utrudnienie konwersji z java.util.Date na klasy JSR310 ” Prawdopodobnie prawda, ale niestety „millis od epoki” stała się niemal uniwersalną reprezentacją czasu, więc dla wszystkiego, co potrzebuje do komunikowania się ze starszymi interfejsami API Java, Javascript, cokolwiek innego, to pominięcie jest prawdziwym kłopotem.
nilskp
Twój fragment kodu u góry jest niepoprawny - musisz pomnożyć getEpochSecond przez 1000.
Tin Man
@nilskp To dwie różne rzeczy. Pytanie brzmi getMillis()jak w getMillis-of-second; mówisz o „millis od epoki”. Ten pierwszy jest nieobecny, jak wyjaśniono w zaakceptowanej odpowiedzi. Ten ostatni jest już dostępny jako Instant.toEpochMillis(). Więc, na przykład LocalDateTime, poszedłbyś:ldt.toInstant(offset).toEpochMillis()
SusanW