¿Por qué las clases Java 8 java.time no tienen un método getMillis ()?

64

Java 8 tiene una biblioteca completamente nueva para fechas y horas en el paquete java.time, lo cual es muy bienvenido para cualquiera que haya tenido que usar JodaTime antes o que tenga problemas para crear sus propios métodos auxiliares de procesamiento de fechas. Muchas clases en este paquete representan marcas de tiempo y tienen métodos auxiliares como getHour()obtener horas de la marca de tiempo, getMinute()obtener minutos de la marca de tiempo, getNano()obtener nanos de la marca de tiempo, etc.

Me di cuenta de que no tienen un método llamado getMillis()para obtener los millis de la marca de tiempo. En cambio, uno tendría que llamar al método get(ChronoField.MILLI_OF_SECOND). A mí me parece una inconsistencia en la biblioteca. ¿Alguien sabe por qué falta un método de este tipo, o dado que Java 8 todavía está en desarrollo, existe la posibilidad de que se agregue más adelante?

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

Las clases definidas aquí representan los principales conceptos de fecha y hora, incluidos instantes, duraciones, fechas, horas, zonas horarias y períodos. Se basan en el sistema de calendario ISO, que es el calendario mundial de facto que sigue las reglas gregorianas prolepticas. Todas las clases son inmutables y seguras para subprocesos.

Cada instancia de fecha y hora se compone de campos que las API ponen convenientemente a disposición. Para acceso de nivel inferior a los campos, consulte el java.time.temporalpaquete. Cada clase incluye soporte para imprimir y analizar todo tipo de fechas y horas. Consulte el java.time.formatpaquete para ver las opciones de personalización ...

Ejemplo de este tipo de clase:
https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html

Una fecha y hora sin zona horaria en el sistema de calendario ISO-8601, como 2007-12-03T10: 15: 30.

LocalDateTimees un objeto de fecha y hora inmutable que representa una fecha y hora, a menudo vista como año-mes-día-hora-minuto-segundo. También se puede acceder a otros campos de fecha y hora, como el día del año, el día de la semana y la semana del año. El tiempo se representa con una precisión de nanosegundos. Por ejemplo, el valor "2 de octubre de 2007 a las 13: 45.30.123456789" se puede almacenar en un LocalDateTime...

Tarmo
fuente
Parece como si quisieran usar el polimorfismo para resolver un montón de métodos llamados get(), en lugar de darles nombres únicos e individuales. Si te molesta, escribe una clase que herede la clase original y coloca tu propio getMillis()método en la nueva clase.
Robert Harvey
@RobertHarvey La mayoría de las clases en el paquete java.time son inmutables y no se pueden extender.
Assylias
2
@RobertHarvey La pregunta para mí no es cómo puedo resolver esto. Simplemente parecía una extraña inconsistencia y me preguntaba si hay una explicación interesante para esto.
Tarmo
Tengo la idea de que algunas arquitecturas / sistemas operativos no admiten de manera confiable milisegundos. En otras palabras, la hora del sistema no se puede recuperar al milisegundo, solo al centisegundo o decisegundo.
Marco
Vea stackoverflow.com/a/23945792/40064 para saber cómo hacerlo a través de la Instantclase
Wim Deblauwe el

Respuestas:

63

JSR-310 se basa en nanosegundos, no milisegundos. Como tal, el conjunto mínimo de métodos sensibles se basa en la hora, los minutos, el segundo y el nanosegundo. La decisión de tener una base de nanosegundos fue una de las decisiones originales del proyecto, y creo firmemente que es correcta.

Agregar un método para milis se superpondría con el de nanosegundo es una forma no obvia. Los usuarios tendrían que pensar si el campo nano era nano-de-segundo o nano-de-milli por ejemplo. Agregar un método adicional confuso no es deseable, por lo que se omitió el método. Como se señaló, la alternativa get(MILLI_OF_SECOND)está disponible.

FWIW, me opondría a agregar el getMillis()método en el futuro.

JodaStephen
fuente
1
He recibido algunas respuestas muy buenas a esta pregunta, pero su respuesta es mi favorita, ya que es breve y, sin embargo, sigue siendo un buen punto y realmente me convence de la necesidad de este enfoque. Gracias.
Tarmo
12
@ s3ib si verifica el perfil de answerer , también notará que él es un líder de especificaciones para la misma API que está preguntando. Esto hace que una respuesta sea tan autoritativa como parece :)
mosquito
Entonces, ¿tener que hacerlo instant.getEpochSecond * 1000 + instant.getNano / 1000000es razonable para poder comunicarse con las API de Java heredadas (en este punto, todas), Javascript, etc.?
nilskp
10
no, en ese caso puede usar instant.toEpochMilli () download.java.net/jdk8/docs/api/java/time/…
JodaStephen
20

Antes de ser parte de openJDK, threeten estaba en github y antes de eso estaba en sourceforge. En aquel entonces, Stephen Colebourne, quien es líder de especificaciones en jsr-310, realizó una encuesta que aún puede encontrar en el sitio de 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

solo el 6.23% eligió la respuesta # 4 y entre ellos aproximadamente el 15% solicitó una getMillis(), es decir, menos del 1% del total de votos.

Probablemente es por eso que no había getMillisen primer lugar y no pude encontrar nada relacionado en la lista de correo de openjdk, por lo que el asunto aparentemente no se discutió después.

asilias
fuente
3
Creo que darles a las personas varias opciones hace que sea más probable que elijan una de esas opciones, incluso si su opción ideal es "otra". Sin embargo, podría estar equivocado.
Allon Guralnek
2
@AllonGuralnek Sí definitivamente, sin embargo, el componente de milisegundos fue importante en la API de fecha porque todo se basó en varios milis desde la época. En la nueva API es menos relevante la OMI. En la mayoría de los casos de uso, necesita una segunda precisión o la mejor precisión disponible (nanos). Puedo estar equivocado.
Assylias
1
Esto parece preguntar sobre la denominación de los métodos, no qué métodos deberían existir.
svick
1
Bien, lo siento, no estaba claro: quise decir la pregunta de la encuesta, que no busca directamente relacionada con esta pregunta.
svick 01 de
15

Las clases que representan tiempos UTC inequívocos (esos son Instant, OffsetDateTime, ZonedDateTime) tienen dos métodos auxiliares para acceder al desplazamiento absoluto desde la época de Java, es decir, lo que llama 'milisegundos de tiempo' en java.util.Date, que podría usar llegar a milisegundos

long getEpochSecond()
int getNano()

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

En la lista de correo jsr 310long getEpochMillis() se discutieron algunas de las razones por las cuales se eligió esto, en lugar de algunas que extraje por conveniencia:

Parece razonable suponer que la precisión de milisegundos no será suficiente. Sin embargo, cualquier cosa mayor que la precisión de nanosegundos parece excesiva

...

Para implementar esto, mi opción preferida sería 64 bit segundos largos (con signo) + 32 bit int nanosegundos (sin signo).

...

Prefiero que la división esté en el segundo nivel, ya que es la unidad de tiempo oficial de SI en ciencia y el estándar más universalmente acordado.

La división a nivel de días es problemática para los instantes, ya que no maneja los segundos bisiestos. Dividir en el nivel de milisegundos, mientras se integra un poco mejor con el resto de Java, parece realmente bastante extraño. Además, pierde en el rango admitido.

Dividirse en el segundo según lo propuesto, da una gama de instantes de nanosegundos durante 290 mil millones de años. Si bien nadie debería usar esa precisión en ese rango de la línea de tiempo, sugeriría que es más fácil soportarlo que bloquearlo. La división en el nivel de días es problemática para los instantes ya que no maneja los segundos bisiestos.

Tengo la sensación de que otra razón era dificultar intencionalmente la conversión de las clases java.util.Date a JSR310, con la esperanza de que los desarrolladores intentaran comprender las diferencias entre las diversas opciones y no solo usar las nuevas clases a ciegas (mal).

En cuanto a por qué la LocalDateTimeclase no tiene esos métodos, posiblemente no puedan existir allí porque LocalDateTimeno está vinculada a la línea de tiempo UTC hasta que decida en qué zona se encuentra o cuál es su compensación UTC, momento en el que tiene un OffsetDateTimeo ZonedDateTime(ambos tienen los métodos necesarios).

Alternativamente, puede definir su propia LOCAL_EPOCHconstante 1970-01-01T00:00:00y luego hacer una MILLIS.between(LOCAL_EPOCH, localTime)para obtener algún tipo de duración en milisegundos. Sin embargo, este valor no será compatible con ningún valor devuelto por System.currentTimeMilliseconds()o java.util.Date.getTime(), a menos que, por supuesto, defina su hora local como hora UTC; pero en este caso también podría usar Instant directamente o OffsetDateTime con ZoneOffset.UTC.

mkadunc
fuente
44
" posiblemente no puedan existir allí porque LocalDateTime no está vinculado a la línea de tiempo UTC " => un LocalDateTime ciertamente podría tener un getMillismétodo que básicamente regresaría getNanos()/1e6; el hecho de que no sea un instante no evita que tenga un milisegundo componente.
Assylias
2
" Tengo la sensación de que otra razón fue dificultar intencionalmente la conversión de las clases java.util.Date a JSR310 " Probablemente cierto, pero desafortunadamente "millis since epoch" se ha convertido en una representación casi universal del tiempo, así que para cualquier cosa que necesite para comunicarse con las API de Java anteriores, Javascript, cualquier otra cosa, esta omisión es una verdadera molestia.
nilskp
Su fragmento de código en la parte superior es incorrecto: debe multiplicar getEpochSecond por 1000.
Tin Man
@nilskp Son dos cosas diferentes. La pregunta es acerca de getMillis()como en getMillis-of-second; estás hablando de "millis desde la época". El primero está ausente como se explica en la respuesta aceptada. Este último ya está disponible como Instant.toEpochMillis(). Entonces, para un LocalDateTime, irías:ldt.toInstant(offset).toEpochMillis()
SusanW