Java último día del problema del mes

Estoy tratando de crear un rango de fechas para cubrir un mes completo, es decir

[fecha de inicio; fecha final]

Como tal, tengo una fecha de referencia y tratar de crear una nueva fecha de la misma. Estoy teniendo problema con el "endDate" porque quiero que esté cerca del final del día (es decir, 23:59:59).

El código que estoy usando es el siguiente:

public static Date previousMonthLastDate(Date referenceDate) { Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); calendar.setTime(referenceDate); calendar.add(Calendar.MONTH, -1); // move to the previous month int lastDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); calendar.set(Calendar.DAY_OF_MONTH, lastDay); // set the time to be the end of the day calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 59); calendar.set(Calendar.SECOND, 59); return calendar.getTime(); } 

Este código funciona como se espera en el emulador de Android. Sin embargo, ejecutarlo en un teléfono real da la fecha equivocada. Como tal, estoy asumiendo que es algún tipo de problema de zona horaria.

En el teléfono, en lugar de dar decir 31 / agosto / 2010, da 01 / Septiembre / 2010. Este valor se establece para que se establezca después de la línea de código que establece el HOUR_OF_DAY a 23.

¿Algunas ideas?

Gracias.

No puedo responder por qué está sucediendo, pero ¿ha intentado establecerlo al primer día del mes siguiente y restar un segundo / milisegundo?

 calendar.set(Calendar.DAY_OF_MONTH, 1); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.MILLISECOND, -1); 

Yo trabajo en algo así:

Con este código, establezco el día en intervalo:

 Date day = new Date() 

Con este código, consigo el intervalo:

 Calendar startDate = Calendar.getInstance(); Calendar endDate = Calendar.getInstance(); // Set time startDate.setTime(day); endDate.setTime(day); startDate.set(Calendar.DAY_OF_MONTH, 1); startDate.set(Calendar.HOUR_OF_DAY, 0); startDate.set(Calendar.MINUTE, 0); startDate.set(Calendar.SECOND, 0); startDate.set(Calendar.MILLISECOND, 0); endDate.set(Calendar.DAY_OF_MONTH, endDate.getActualMaximum(Calendar.DAY_OF_MONTH)); endDate.set(Calendar.HOUR_OF_DAY, 23); endDate.set(Calendar.MINUTE, 59); endDate.set(Calendar.SECOND, 59); 

Si desea que el huso horario dependa de la configuración del teléfono, no debe forzar un huso horario al crear el calendario. Solo usa:

 Calendar calendar = Calendar.getInstance(); 

La API de calendario le ofrece esta funcionalidad de la caja, aquí es un truco para hacerlo:

 // Get the instance of the Calendar. Calendar calendar = Calendar.getInstance(); // Set the date of the First day of Month calendar.set(Calendar.DAY_OF_MONTH, 1); // Roll it to previous day of Year to get the Last day of Month calendar.roll(Calendar.DAY_OF_YEAR, -1); 

Editar: También tiene que establecer las horas, minutos, segundos y milisegundos.

 calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); 

Tl dr

 ZoneId z = ZoneId.of( "America/Montreal" ); LocalDate today = LocalDate.now( z ); ZonedDateTime start = today.with( TemporalAdjusters.firstDayOfMonth() ) .atStartOfDay( z ) ; ZonedDateTime stop = today.with( TemporalAdjusters.firstDayOfNextMonth() ) .atStartOfDay( z ) ; 
  • La determinación de una fecha requiere una zona horaria.
  • Es mejor especificar explícitamente que confiar implícitamente en la zona horaria predeterminada actual de JVM.

Evite las clases heredadas

Está utilizando las antiguas clases de fecha y hora problemáticas, ahora heredadas, suplantadas por las clases java.time.

Uso de java.time

Este trabajo es mucho más fácil con las clases java.time.

LocalDate

La clase LocalDate representa un valor de fecha única sin hora del día y sin zona horaria.

Zona horaria

Una zona horaria es crucial para determinar una fecha. Para cualquier momento dado, la fecha varía alrededor del globo por la zona. Por ejemplo, unos pocos minutos después de la medianoche en París Francia es un nuevo día, mientras que todavía "ayer" en Montreal Quebec .

Especifique un nombre de zona horaria adecuado en el formato de continent/region , como America/Montreal , Africa/Casablanca o Pacific/Auckland . Nunca utilice la abreviatura de 3-4 letras como EST o IST ya que no son zonas horarias verdaderas, no están estandarizadas y ni siquiera son únicas (!).

 ZoneId z = ZoneId.of( "America/Montreal" ); LocalDate today = LocalDate.now( z ); 

Siempre especifique explícitamente la zona horaria. Si se omite, la zona horaria predeterminada actual de la JVM se aplica implícitamente. Este valor predeterminado puede cambiarse en cualquier momento por cualquier código de cualquier aplicación dentro de la JVM. Por lo tanto, si es crucial, solicite al usuario la zona horaria deseada / esperada. Si no es crucial, puede pedir que el valor predeterminado haga explícitas sus intenciones en el código en lugar de la ambigüedad de confiar en el valor predeterminado implícito.

 ZoneId z = ZoneId.systemDefault(); // Get JVM's current default time zone. LocalDate today = LocalDate.now( z ); 

TemporalAdjuster

La interfaz TemporalAdjuster proporciona clases que pueden ajustar los valores de fecha y hora. La clase TemporalAdjusters proporciona varias implementaciones prácticas.

 LocalDate firstOfThisMonth = today.with( TemporalAdjusters.firstDayOfMonth() ); 

ZonedDateTime

Para convertir esa fecha sólo en una fecha con hora del día, aplique una zona horaria ZoneId para obtener un objeto ZonedDateTime .

No asuma que el primer momento del día es 00:00:00. Debido a anomalías como el horario de verano (DST), el primer momento podría ser algo como el tiempo 01:00:00. Deje que java.time averigüe esto llamando a atStartOfDay .

 ZonedDateTime zdtStartOfMonth = firstOfThisMonth.atStartOfDay( z ); 

Medio abierto

Usted está tomando la dirección equivocada tratando de determinar el último momento del mes. Ese último momento tiene un segundo fraccionario infinitamente divisible. Tratar de resolver a una granularidad particular es poco aconsejable ya que diferentes sistemas utilizan granularidades diferentes. Las viejas clases de fecha y hora de Java usan milisegundos, algunas bases de datos como Postgres utilizan microsegundos, las clases java.time usan nanosegundos y otros sistemas usan otras variaciones.

El enfoque más sabio utilizado comúnmente en el trabajo de fecha y hora para definir períodos de tiempo es Half-Open, donde el principio es inclusivo mientras que el final es exclusivo . Esto significa que un mes comienza en el primer momento del día del primero del mes y corre hasta, pero no incluyendo, el primer momento del primer del mes siguiente .

 LocalDate firstOfNextMonth = today.with( TemporalAdjusters.firstOfNextMonth() ); 

Ajuste en una zona horaria para obtener un momento específico.

 ZonedDateTime zdtStartOfNextMonth = firstOfNextMonth.atStartOfDay( z ); 

La lógica para comparar un momento con este lapso de tiempo es "¿Es este momento (a) igual o posterior al comienzo, y (b) menor que el final?". Observe la falta de "o es igual" en la parte "b". Eso significa que estamos corriendo hasta, pero sin incluir, el final.

Además, una forma más corta de decir parte 'a' no es "antes del principio". Así que podemos preguntar más sencillamente, "¿Este momento no es antes del principio Y es antes del final?".

 ZonedDateTime moment = ZonedDateTime.now( z ); Boolean spanContainsMoment = ( ! moment.isBefore( zdtStartOfMonth ) ) && ( moment.isBefore( zdtStartOfNextMonth ) ) ; 

Por cierto, el formato estándar ISO 8601 para dar formato a una representación textual de un lapso de tiempo utiliza un carácter de barra inclinada para unir el principio y el final.

 String output = zdtStartOfMonth.toString() + "/" + zdtStartOfNextMonth.toString() ; 

Interval

Puede representar este lapso de tiempo utilizando la clase Interval en la biblioteca ThreeTen-Extra . Esa clase registra el principio y termina en UTC como objetos Instant . Puede extraer un Instant de un objeto ZonedDateTime .

 Interval interval = Interval.of( zdtStartOfMonth.toInstant() , zdtStartOfNextMonth.toInstant() ); 

YearMonth

Por cierto, puede encontrar la clase YearMonth útil en su trabajo.


Acerca de java.time

El framework java.time está integrado en Java 8 y posterior. Estas clases suplantan las viejas clases de fecha-hora heredadas , como java.util.Date , Calendar y SimpleDateFormat .

El proyecto Joda-Time , ahora en modo de mantenimiento , recomienda la migración a las clases java.time .

Para obtener más información, consulte el Tutorial de Oracle . Y busca Stack Overflow para muchos ejemplos y explicaciones. La especificación es JSR 310 .

Dónde obtener las clases java.time?

  • Java SE 8 y SE 9 y posterior
    • Incorporado.
    • Parte de la API Java estándar con una implementación integrada.
    • Java 9 agrega algunas características y correcciones menores.
  • Java SE 6 y SE 7
    • Gran parte de la funcionalidad de java.time se retroporta a Java 6 & 7 en ThreeTen-Backport .
  • Androide
    • El proyecto ThreeTenABP adapta específicamente a ThreeTen-Backport (mencionado anteriormente) para Android.
    • Consulte Cómo utilizar ThreeTenABP ….

El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un terreno probatorio para posibles adiciones futuras a java.time. Puede encontrar algunas clases útiles como Interval , YearWeek , YearQuarter y más .

  • Android Thread.sleep () en AsyncTask congelar la interfaz de usuario
  • Recomienda una biblioteca de juegos Java / Android - tarjeta, tablero, etc.?
  • Analizar un archivo de volcado de memoria HPROF desde la línea de comandos programmically
  • Error al agregar un texto de edición en eclipse
  • Android: ¿Está onPause () garantizado para ser llamado después de finish ()?
  • Cómo retrasar un bucle en android sin usar thread.sleep?
  • ¿Existe un filtro "tee" simple para los flujos de Java?
  • ¿Existe algún #IF y #CONST equivalente .NET en Java / Android?
  • ¿Cómo envío un archivo csv / texto desde un teléfono Android a una impresora wifi?
  • Ajustar un ImageView (y su src) al ancho de diseño y hacer su altura proporcional
  • Obtenga el tamaño de RAM total que utiliza Aplicación en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.