Necesito encontrar el número de días entre dos fechas : una es de un informe y la otra es la fecha actual. Mi fragmento:
int age=calculateDifference(agingDate, today);
Aquí calculateDifference
hay un método privado, agingDate
y today
son Date
objetos, solo para su aclaración. He seguido dos artículos de un foro de Java, Thread 1 / Thread 2 .
Funciona bien en un programa independiente, aunque cuando incluyo esto en mi lógica para leer el informe, obtengo una diferencia inusual en los valores.
¿Por qué está sucediendo y cómo puedo solucionarlo?
EDITAR:
Obtengo una mayor cantidad de días en comparación con la cantidad real de días.
public static int calculateDifference(Date a, Date b)
{
int tempDifference = 0;
int difference = 0;
Calendar earlier = Calendar.getInstance();
Calendar later = Calendar.getInstance();
if (a.compareTo(b) < 0)
{
earlier.setTime(a);
later.setTime(b);
}
else
{
earlier.setTime(b);
later.setTime(a);
}
while (earlier.get(Calendar.YEAR) != later.get(Calendar.YEAR))
{
tempDifference = 365 * (later.get(Calendar.YEAR) - earlier.get(Calendar.YEAR));
difference += tempDifference;
earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
}
if (earlier.get(Calendar.DAY_OF_YEAR) != later.get(Calendar.DAY_OF_YEAR))
{
tempDifference = later.get(Calendar.DAY_OF_YEAR) - earlier.get(Calendar.DAY_OF_YEAR);
difference += tempDifference;
earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
}
return difference;
}
Nota :
Desafortunadamente, ninguna de las respuestas me ayudó a resolver el problema. Logré este problema con la ayuda de la biblioteca Joda-time .
java.util.Date
,java.util.Calendar
yjava.text.SimpleDateFormat
ahora están legado , suplantados por los java.time clases. Consulte el tutorial de Oracle . Asimismo, el proyecto Joda-Time se encuentra ahora en modo de mantenimiento , y el equipo aconseja la migración a las clases java.time.Respuestas:
Le sugiero que use la excelente biblioteca Joda Time en lugar del defectuoso java.util.Date y amigos. Simplemente podrías escribir
import java.util.Date; import org.joda.time.DateTime; import org.joda.time.Days; Date past = new Date(110, 5, 20); // June 20th, 2010 Date today = new Date(110, 6, 24); // July 24th int days = Days.daysBetween(new DateTime(past), new DateTime(today)).getDays(); // => 34
fuente
Puede que sea demasiado tarde para unirme al juego, pero ¿qué diablos, eh? :)
¿Crees que esto es un problema de subprocesos? ¿Cómo está utilizando la salida de este método, por ejemplo? O
¿Podemos cambiar su código para hacer algo tan simple como:
Calendar calendar1 = Calendar.getInstance(); Calendar calendar2 = Calendar.getInstance(); calendar1.set(<your earlier date>); calendar2.set(<your current date>); long milliseconds1 = calendar1.getTimeInMillis(); long milliseconds2 = calendar2.getTimeInMillis(); long diff = milliseconds2 - milliseconds1; long diffSeconds = diff / 1000; long diffMinutes = diff / (60 * 1000); long diffHours = diff / (60 * 60 * 1000); long diffDays = diff / (24 * 60 * 60 * 1000); System.out.println("\nThe Date Different Example"); System.out.println("Time in milliseconds: " + diff + " milliseconds."); System.out.println("Time in seconds: " + diffSeconds + " seconds."); System.out.println("Time in minutes: " + diffMinutes + " minutes."); System.out.println("Time in hours: " + diffHours + " hours."); System.out.println("Time in days: " + diffDays + " days."); }
fuente
El diff / (24 * etc) no tiene en cuenta la zona horaria, por lo que si su zona horaria predeterminada tiene un horario de verano, puede desechar el cálculo.
Este enlace tiene una pequeña implementación.
Aquí está la fuente del enlace anterior en caso de que el enlace se caiga:
/** Using Calendar - THE CORRECT WAY**/ public static long daysBetween(Calendar startDate, Calendar endDate) { //assert: startDate must be before endDate Calendar date = (Calendar) startDate.clone(); long daysBetween = 0; while (date.before(endDate)) { date.add(Calendar.DAY_OF_MONTH, 1); daysBetween++; } return daysBetween; }
y
/** Using Calendar - THE CORRECT (& Faster) WAY**/ public static long daysBetween(final Calendar startDate, final Calendar endDate) { //assert: startDate must be before endDate int MILLIS_IN_DAY = 1000 * 60 * 60 * 24; long endInstant = endDate.getTimeInMillis(); int presumedDays = (int) ((endInstant - startDate.getTimeInMillis()) / MILLIS_IN_DAY); Calendar cursor = (Calendar) startDate.clone(); cursor.add(Calendar.DAY_OF_YEAR, presumedDays); long instant = cursor.getTimeInMillis(); if (instant == endInstant) return presumedDays; final int step = instant < endInstant ? 1 : -1; do { cursor.add(Calendar.DAY_OF_MONTH, step); presumedDays += step; } while (cursor.getTimeInMillis() != endInstant); return presumedDays; }
fuente
while
debería serlo.while (cursor.getTimeInMillis() <= endInstant);
De lo contrario, obtienes un bucle infinito si menos de un día.java.time
En Java 8 y versiones posteriores, use el marco java.time ( Tutorial ).
Duration
La
Duration
clase representa un lapso de tiempo como una cantidad de segundos más una fracción de segundo. Puede contar días, horas, minutos y segundos.ZonedDateTime now = ZonedDateTime.now(); ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10); Duration duration = Duration.between(oldDate, now); System.out.println(duration.toDays());
ChronoUnit
Si todo lo que necesita es la cantidad de días, alternativamente puede usar la enumeración . Observe que los métodos de cálculo devuelven a en lugar de .
ChronoUnit
long
int
long days = ChronoUnit.DAYS.between( then, now );
fuente
import java.util.Calendar; import java.util.Date; public class Main { public static long calculateDays(String startDate, String endDate) { Date sDate = new Date(startDate); Date eDate = new Date(endDate); Calendar cal3 = Calendar.getInstance(); cal3.setTime(sDate); Calendar cal4 = Calendar.getInstance(); cal4.setTime(eDate); return daysBetween(cal3, cal4); } public static void main(String[] args) { System.out.println(calculateDays("2012/03/31", "2012/06/17")); } /** Using Calendar - THE CORRECT WAY**/ public static long daysBetween(Calendar startDate, Calendar endDate) { Calendar date = (Calendar) startDate.clone(); long daysBetween = 0; while (date.before(endDate)) { date.add(Calendar.DAY_OF_MONTH, 1); daysBetween++; } return daysBetween; } }
fuente
Depende de lo que defina como diferencia. Para comparar dos fechas a medianoche puedes hacerlo.
long day1 = ...; // in milliseconds. long day2 = ...; // in milliseconds. long days = (day2 - day1) / 86400000;
fuente
Solución que usa la diferencia entre milisegundos de tiempo, con el redondeo correcto para las fechas de DST:
public static long daysDiff(Date from, Date to) { return daysDiff(from.getTime(), to.getTime()); } public static long daysDiff(long from, long to) { return Math.round( (to - from) / 86400000D ); // 1000 * 60 * 60 * 24 }
Una nota: por supuesto, las fechas deben estar en alguna zona horaria.
El código importante:
Math.round( (to - from) / 86400000D )
Si no desea una ronda, puede usar fechas UTC,
fuente
Ilustración del problema: (Mi código calcula delta en semanas, pero el mismo problema se aplica con delta en días)
Aquí hay una implementación de aspecto muy razonable:
public static final long MILLIS_PER_WEEK = 7L * 24L * 60L * 60L * 1000L; static public int getDeltaInWeeks(Date latterDate, Date earlierDate) { long deltaInMillis = latterDate.getTime() - earlierDate.getTime(); int deltaInWeeks = (int)(deltaInMillis / MILLIS_PER_WEEK); return deltaInWeeks; }
Pero esta prueba fallará:
public void testGetDeltaInWeeks() { delta = AggregatedData.getDeltaInWeeks(dateMar09, dateFeb23); assertEquals("weeks between Feb23 and Mar09", 2, delta); }
La razón es:
pero cualquiera que mire un calendario estaría de acuerdo en que la respuesta es 2.
fuente
Yo uso esta funcion:
DATEDIFF("31/01/2016", "01/03/2016") // me return 30 days
mi función:
import java.util.Date; public long DATEDIFF(String date1, String date2) { long MILLISECS_PER_DAY = 24 * 60 * 60 * 1000; long days = 0l; SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); // "dd/MM/yyyy HH:mm:ss"); Date dateIni = null; Date dateFin = null; try { dateIni = (Date) format.parse(date1); dateFin = (Date) format.parse(date2); days = (dateFin.getTime() - dateIni.getTime())/MILLISECS_PER_DAY; } catch (Exception e) { e.printStackTrace(); } return days; }
fuente
Mire los métodos getFragmentInDays en esta clase de apache commons-lang
DateUtils
.fuente
Basado en la respuesta de @ Mad_Troll, desarrollé este método.
He ejecutado alrededor de 30 casos de prueba en su contra, es el único método que maneja correctamente los fragmentos de tiempo sub-día.
Ejemplo: si pasa ahora y ahora + 1 milisegundo, sigue siendo el mismo día. Haciendo
1-1-13 23:59:59.098
que1-1-13 23:59:59.099
devuelve 0 días, correctamente; muchos de los otros métodos publicados aquí no harán esto correctamente.Vale la pena señalar que no le importa de qué manera los coloque, si su fecha de finalización es anterior a su fecha de inicio, contará hacia atrás.
/** * This is not quick but if only doing a few days backwards/forwards then it is very accurate. * * @param startDate from * @param endDate to * @return day count between the two dates, this can be negative if startDate is after endDate */ public static long daysBetween(@NotNull final Calendar startDate, @NotNull final Calendar endDate) { //Forwards or backwards? final boolean forward = startDate.before(endDate); // Which direction are we going final int multiplier = forward ? 1 : -1; // The date we are going to move. final Calendar date = (Calendar) startDate.clone(); // Result long daysBetween = 0; // Start at millis (then bump up until we go back a day) int fieldAccuracy = 4; int field; int dayBefore, dayAfter; while (forward && date.before(endDate) || !forward && endDate.before(date)) { // We start moving slowly if no change then we decrease accuracy. switch (fieldAccuracy) { case 4: field = Calendar.MILLISECOND; break; case 3: field = Calendar.SECOND; break; case 2: field = Calendar.MINUTE; break; case 1: field = Calendar.HOUR_OF_DAY; break; default: case 0: field = Calendar.DAY_OF_MONTH; break; } // Get the day before we move the time, Change, then get the day after. dayBefore = date.get(Calendar.DAY_OF_MONTH); date.add(field, multiplier); dayAfter = date.get(Calendar.DAY_OF_MONTH); // This shifts lining up the dates, one field at a time. if (dayBefore == dayAfter && date.get(field) == endDate.get(field)) fieldAccuracy--; // If day has changed after moving at any accuracy level we bump the day counter. if (dayBefore != dayAfter) { daysBetween += multiplier; } } return daysBetween; }
Puede eliminar las
@NotNull
anotaciones, Intellij las utiliza para realizar análisis de código sobre la marchafuente
Dices que "funciona bien en un programa independiente", pero que obtienes "valores de diferencia inusuales" cuando "incluyes esto en mi lógica para leer el informe". Eso sugiere que su informe tiene algunos valores para los que no funciona correctamente y su programa independiente no tiene esos valores. En lugar de un programa independiente, sugiero un caso de prueba. Escriba un caso de prueba como lo haría con un programa independiente, subclasificando de la clase TestCase de JUnit. Ahora puede ejecutar un ejemplo muy específico, sabiendo qué valor espera (y no lo dé hoy por el valor de prueba, porque hoy cambia con el tiempo). Si ingresa los valores que usó en el programa independiente, sus pruebas probablemente pasarán. Eso es genial, quieres que esos casos sigan funcionando. Ahora, agregue un valor de su informe, uno que no t funciona bien. Su nueva prueba probablemente fallará. Averigua por qué está fallando, arréglalo y ponte verde (todas las pruebas pasan). Ejecute su informe. Mira lo que todavía está roto; escribir una prueba; hazlo pasar. Muy pronto verá que su informe está funcionando.
fuente
¿¿Cien líneas de código para esta función básica ???
Solo un método simple:
protected static int calculateDayDifference(Date dateAfter, Date dateBefore){ return (int)(dateAfter.getTime()-dateBefore.getTime())/(1000 * 60 * 60 * 24); // MILLIS_IN_DAY = 1000 * 60 * 60 * 24; }
fuente
public static int getDifferenceIndays(long timestamp1, long timestamp2) { final int SECONDS = 60; final int MINUTES = 60; final int HOURS = 24; final int MILLIES = 1000; long temp; if (timestamp1 < timestamp2) { temp = timestamp1; timestamp1 = timestamp2; timestamp2 = temp; } Calendar startDate = Calendar.getInstance(TimeZone.getDefault()); Calendar endDate = Calendar.getInstance(TimeZone.getDefault()); endDate.setTimeInMillis(timestamp1); startDate.setTimeInMillis(timestamp2); if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) { int day1 = endDate.get(Calendar.DAY_OF_MONTH); int day2 = startDate.get(Calendar.DAY_OF_MONTH); if (day1 == day2) { return 0; } else { return 1; } } int diffDays = 0; startDate.add(Calendar.DAY_OF_MONTH, diffDays); while (startDate.before(endDate)) { startDate.add(Calendar.DAY_OF_MONTH, 1); diffDays++; } return diffDays; }
fuente
ThreeTen-Extra
La respuesta de Vitalii Fedorenko es correcta y describe cómo realizar este cálculo de una manera moderna con las clases java.time (
Duration
&ChronoUnit
) integradas en Java 8 y posteriores (y adaptadas a Java 6 y 7 y a Android ).Days
Si usa varios días de forma rutinaria en su código, puede reemplazar meros enteros con el uso de una clase. La
Days
clase se puede encontrar en el proyecto ThreeTen-Extra , una extensión de java.time y campo de pruebas para posibles adiciones futuras a java.time. LaDays
clase proporciona una forma segura de representar un número de días en su solicitud. La clase incluye constantes convenientes paraZERO
yONE
.Dados los viejos
java.util.Date
objetos obsoletos de la Pregunta, primero conviértalos enjava.time.Instant
objetos modernos . Las antiguas clases de fecha y hora tienen métodos recientemente agregados para facilitar la conversión a java.time, comojava.util.Date::toInstant
.Instant start = utilDateStart.toInstant(); // Inclusive. Instant stop = utilDateStop.toInstant(); // Exclusive.
Pase ambos
Instant
objetos al método de fábrica paraorg.threeten.extra.Days
.En la implementación actual (2016-06), esta es una llamada de contenedor
java.time.temporal.ChronoUnit.DAYS.between
, lea elChronoUnit
documento de la clase para obtener más detalles. Para ser claros: todas las mayúsculasDAYS
están en la enumeración,ChronoUnit
mientras que initial-capDays
es una clase de ThreeTen-Extra.Puede pasar estos
Days
objetos alrededor de su propio código. Puede serializar a una cadena en el formato estándar ISO 8601 llamandotoString
. Este formato dePnD
utiliza unaP
para marcar el comienzo yD
significa "días", con un número de días en el medio. Tanto las clases java.time como ThreeTen-Extra utilizan estos formatos estándar de forma predeterminada al generar y analizar cadenas que representan valores de fecha y hora.Days days = Days.parse( "P3D" );
fuente
Este código calcula los días entre 2 cadenas de fechas:
static final long MILLI_SECONDS_IN_A_DAY = 1000 * 60 * 60 * 24; static final String DATE_FORMAT = "dd-MM-yyyy"; public long daysBetween(String fromDateStr, String toDateStr) throws ParseException { SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT); Date fromDate; Date toDate; fromDate = format.parse(fromDateStr); toDate = format.parse(toDateStr); return (toDate.getTime() - fromDate.getTime()) / MILLI_SECONDS_IN_A_DAY; }
fuente
Si está buscando una solución que devuelva el número adecuado de días entre, por ejemplo,
11/30/2014 23:59
y12/01/2014 00:01
aquí está la solución con Joda Time.private int getDayDifference(long past, long current) { DateTime currentDate = new DateTime(current); DateTime pastDate = new DateTime(past); return currentDate.getDayOfYear() - pastDate.getDayOfYear(); }
Esta implementación regresará
1
como una diferencia en días. La mayoría de las soluciones publicadas aquí calculan la diferencia en milisegundos entre dos fechas. Significa que0
se devolvería porque solo hay 2 minutos de diferencia entre estas dos fechas.fuente
Debería utilizar la biblioteca Joda Time porque Java Util Date a veces devuelve valores incorrectos.
Joda vs Java Util Date
Por ejemplo, días entre ayer (dd-mm-aaaa, 12-07-2016) y el primer día del año 1957 (dd-mm-aaaa, 01-01-1957):
public class Main { public static void main(String[] args) { SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); Date date = null; try { date = format.parse("12-07-2016"); } catch (ParseException e) { e.printStackTrace(); } //Try with Joda - prints 21742 System.out.println("This is correct: " + getDaysBetweenDatesWithJodaFromYear1957(date)); //Try with Java util - prints 21741 System.out.println("This is not correct: " + getDaysBetweenDatesWithJavaUtilFromYear1957(date)); } private static int getDaysBetweenDatesWithJodaFromYear1957(Date date) { DateTime jodaDateTime = new DateTime(date); DateTimeFormatter formatter = DateTimeFormat.forPattern("dd-MM-yyyy"); DateTime y1957 = formatter.parseDateTime("01-01-1957"); return Days.daysBetween(y1957 , jodaDateTime).getDays(); } private static long getDaysBetweenDatesWithJavaUtilFromYear1957(Date date) { SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); Date y1957 = null; try { y1957 = format.parse("01-01-1957"); } catch (ParseException e) { e.printStackTrace(); } return TimeUnit.DAYS.convert(date.getTime() - y1957.getTime(), TimeUnit.MILLISECONDS); }
Así que te recomiendo que uses la biblioteca de Joda Time.
fuente
Lo hice de esta manera. es fácil :)
Date d1 = jDateChooserFrom.getDate(); Date d2 = jDateChooserTo.getDate(); Calendar day1 = Calendar.getInstance(); day1.setTime(d1); Calendar day2 = Calendar.getInstance(); day2.setTime(d2); int from = day1.get(Calendar.DAY_OF_YEAR); int to = day2.get(Calendar.DAY_OF_YEAR); int difference = to-from;
fuente