java - examples - Uso recomendado para Joda-Time''s DateMidnight
jodatime java 8 (5)
tl; dr
Use java.time clases de java.time , específicamente LocalDate::atStartOfDay
lugar de la idea resbaladiza de "medianoche".
ZoneId z = ZoneId.of( "America/Montreal" ); // A time zone.
ZonedDateTime todayStart = LocalDate.now( z ).atStartOfDay( z ); // Produces a LocalDate (a whole day without time zone), then transforms into a `ZonedDateTime` (a moment on the timeline)
java.time
Como el proyecto Joda-Time ahora está en modo de mantenimiento y el equipo recomienda la migración a las clases java.time, agregaré un ejemplo usando java.time.
Si desea representar todo el día como un todo, use la clase LocalDate
. La clase LocalDate
representa un valor de solo fecha sin hora del día y sin zona horaria.
Un huso horario es crucial para determinar una fecha. Para cualquier momento dado, la fecha varía alrededor del mundo por zona. Por ejemplo, unos minutos después de la medianoche en París, Francia es un nuevo día cuando todavía está "ayer" en Montreal Québec .
ZoneId z = ZoneId.of( “America/Montreal” );
LocalDate today = LocalDate.now( z );
Como se discutió en esta página, tratar de señalar el final del día es una mala práctica. Por un lado, tiene el problema de una fracción infinitamente divisible durante el último segundo del día. ¿Resuelve milisegundos, microsegundos, nanosegundos o algo más, ya que todos estos son de uso común? En su lugar, use el primer momento del nuevo día.
Deje que java.time determine el tiempo del reloj de pared de ese primer momento del día. No asuma que el tiempo será 00:00:00
ya que anomalías como el horario de verano (DST) pueden significar que el primer momento es un horario como 01:00:00
. Dichos ajustes de horario de verano se usan actualmente en zonas horarias de varios países.
Entonces, para obtener un momento, un punto real en la línea de tiempo, para el inicio del día, llame a LocalDate::atStartOfDay
. Observe que esta es una versión más corta del nombre del método que la utilizada en el método Joda-Time withTimeAtStartOfDay
. Especifique la zona horaria deseada / esperada en un ZoneId
para producir un objeto ZonedDateTime
.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = today.atStartOfDay( z );
Medio abierto
Entonces, ¿cómo representar un lapso de tiempo? Si quiero señalar el comienzo y el final de este solo día, ¿cómo lo hago mientras sigo este consejo? La solución comúnmente utilizada en el trabajo de fecha y hora es el enfoque Half-Open. En este enfoque, el comienzo del lapso es inclusivo, mientras que el final es exclusivo . Por lo tanto, "hoy" significa comenzar con el primer momento del día y continuar hasta el primer momento del día siguiente, pero sin incluirlo.
ZonedDateTime zdtStartToday = LocalDate.now( z ).atStartOfDay( z );
ZonedDateTime zdtStartTomorrow = zdtStartToday.plusDays( 1 );
Por cierto, el proyecto ThreeTen-Extra tiene una práctica clase Interval
para tales períodos de tiempo.
Interval todayInterval = Interval.of(
zdtStartToday.toInstant() ,
zdtStartTomorrow.toInstant()
)
Acerca de java.time
El marco java.time está integrado en Java 8 y posterior. Estas clases suplantan a las antiguas clases problemáticas de fecha y hora, como java.util.Date
, .Calendar
y java.text.SimpleDateFormat
.
El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a java.time.
Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones.
Gran parte de la funcionalidad de java.time se transfiere a Java 6 y 7 en ThreeTen-Backport y se adapta mejor a Android en ThreeTenABP (ver Cómo usar ... ).
El proyecto ThreeTen-Extra amplía java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time. Puede encontrar algunas clases útiles aquí, como Interval
, YearWeek
, YearQuarter
y more .
El javdoc para LocalDate#toDateMidnight
lee de la siguiente manera:
A partir de la v1.5, se recomienda evitar DateMidnight y usar toDateTimeAtStartOfDay () en su lugar debido a la excepción que se detalla a continuación.
Este método lanzará una excepción si la zona horaria predeterminada cambia al horario de verano a medianoche y este día local representa esa fecha de cambio. El problema es que no existe la medianoche en la fecha requerida y, como tal, se lanza una excepción.
El hecho de que la medianoche no exista en ciertas zonas horarias parece una razón suficiente para evitar el uso de DateMidnight
completo (suponiendo que su código no utiliza una zona horaria fija que se sabe que no tiene esta situación de horario de verano y nunca necesitará usar diferentes zonas horarias en el futuro).
Sin embargo, DateMidnight
no está en desuso y no hay recomendaciones o advertencias similares en el javadoc para la clase DateMidnight
. Además, el constructor de DateMidnight
acepta felizmente un instante y una zona horaria tales que la medianoche no existe en el día dado, en lugar de arrojar una IllegalArgumentException
como LocalDate#toDateMidnight
. El DateMidnight
resultante se comporta como un DateTime
con tiempo al inicio del día.
Cuando la medianoche no existe en un día determinado, ¿por qué LocalDate#toDateMidnight
lanza una excepción mientras que el constructor de DateMidnight
no? ¿Cuál es el caso de uso recomendado para DateMidnight
si hay alguno?
Mira la excepción que tenía en mi código
Illegal instant due to time zone offset transition (daylight savings time ''gap''): 2015-03-27T00:00:00.000 (Asia/Amman)
org.joda.time.IllegalInstantException: Illegal instant due to time zone offset transition (daylight savings time ''gap''): 2015-03-27T00:00:00.000 (Asia/Amman)
Ahora lo resolví usando
LocalDate currentDate=new LocalDate();
someMethodSetsTheDate(currentDate.toDateTimeAtStartOfDay().toDate());
En lugar de
someMethodSetsTheDate(new DateMidnight(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth()).toDate());
Ahora mi recomendación es usar .toDateTimeAtStartOfDay () para evitar excepciones similares.
Por favor, no dude en editar mi respuesta Gracias
No hay una buena razón para usar DateMidnight
. LocalDate
es la mejor opción. Eso es porque la medianoche no ocurre una vez al año en ciertas zonas horarias, estropeando completamente la usabilidad de la clase y creando errores en las aplicaciones.
El constructor se corrigió para evitar el peor problema, sin embargo, ver un objeto DateMidnight
con el valor de milisegundos interno apuntando a la 01:00 no es exactamente genial.
O mejor, utilice el método toDateTimeAtStartOfDay
directamente para eludir la creación del objeto DateTime
(en relación con la respuesta anterior ).
new LocalDate().toDateTimeAtStartOfDay( myDateTimeZone )
nuevo DateTime (). withTimeAtStartOfDay() se recomienda.