Calcular días entre dos fechas con Java

150

Quiero un programa Java que calcule días entre dos fechas.

  1. Escriba la primera fecha (notación alemana; con espacios en blanco: "dd mm aaaa")
  2. Escriba la segunda fecha.
  3. El programa debe calcular el número de días entre las dos fechas.

¿Cómo puedo incluir los años bisiestos y el verano?

Mi código:

import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;

public class NewDateDifference {

    public static void main(String[] args) {

        System.out.print("Insert first date: ");
        Scanner s = new Scanner(System.in);
        String[] eingabe1 = new String[3];

        while (s.hasNext()) {
            int i = 0;
            insert1[i] = s.next();
            if (!s.hasNext()) {
                s.close();
                break;
            }
            i++;
        }

        System.out.print("Insert second date: ");
        Scanner t = new Scanner(System.in);
        String[] insert2 = new String[3];

        while (t.hasNext()) {
            int i = 0;
            insert2[i] = t.next();
            if (!t.hasNext()) {
                t.close();
                break;
            }
            i++;
        }

        Calendar cal = Calendar.getInstance();

        cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(insert1[0]));
        cal.set(Calendar.MONTH, Integer.parseInt(insert1[1]));
        cal.set(Calendar.YEAR, Integer.parseInt(insert1[2]));
        Date firstDate = cal.getTime();

        cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(insert2[0]));
        cal.set(Calendar.MONTH, Integer.parseInt(insert2[1]));
        cal.set(Calendar.YEAR, Integer.parseInt(insert2[2]));
        Date secondDate = cal.getTime();


        long diff = secondDate.getTime() - firstDate.getTime();

        System.out.println ("Days: " + diff / 1000 / 60 / 60 / 24);
    }
}
usuario3025448
fuente
¿Qué no funciona? ¿Está fallando? ¿Te está dando números incorrectos?
jens108
¿Dónde está la declaración de la matriz: insert1?
Rhys
1
insert1 = eingabe1 en alemán :)
peter.petrov
@ peter.petrov Ah, ya veo!
Rhys
Creo que está teniendo problemas con mmy MM: P
Sage

Respuestas:

229

ACTUALIZACIÓN: La respuesta original de 2013 ahora está desactualizada porque algunas de las clases han sido reemplazadas. La nueva forma de hacerlo es usar las nuevas java.timeclases.

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";

try {
    LocalDateTime date1 = LocalDate.parse(inputString1, dtf);
    LocalDateTime date2 = LocalDate.parse(inputString2, dtf);
    long daysBetween = Duration.between(date1, date2).toDays();
    System.out.println ("Days: " + daysBetween);
} catch (ParseException e) {
    e.printStackTrace();
}

Tenga en cuenta que esta solución le dará la cantidad de días reales de 24 horas, no la cantidad de días calendario. Para este último, use

long daysBetween = ChronoUnit.DAYS.between(date1, date2)

Respuesta original (desactualizada a partir de Java 8)

Está haciendo algunas conversiones con sus cadenas que no son necesarias. Hay una SimpleDateFormatclase para ello: intente esto:

SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";

try {
    Date date1 = myFormat.parse(inputString1);
    Date date2 = myFormat.parse(inputString2);
    long diff = date2.getTime() - date1.getTime();
    System.out.println ("Days: " + TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS));
} catch (ParseException e) {
    e.printStackTrace();
}

EDITAR: dado que ha habido algunas discusiones sobre la corrección de este código: de hecho se ocupa de los años bisiestos. Sin embargo, la TimeUnit.DAYS.convertfunción pierde precisión ya que los milisegundos se convierten en días (consulte el documento vinculado para obtener más información). Si esto es un problema, difftambién se puede convertir a mano:

float days = (diff / (1000*60*60*24));

Tenga en cuenta que este es un floatvalor, no necesariamente un int.

jens108
fuente
40
Esta es una mala implementación que no tiene en cuenta los años bisiestos correctamente.
Groovy Ed
3
TimeUnit.DAYS.convert (diff, TimeUnit.MILLISECONDS)); <3
Guihgo
3
@GroovyEd Por lo que he probado, parece que este código no tiene ningún problema con los años bisiestos. Tenga en cuenta que TimeUnit.Days.convert () ignorará las unidades restantes, por ejemplo, la conversión de 999 milisegundos a segundos da como resultado 0. Esto significa que si usa la nueva Fecha () como uno de los objetos de Fecha, podría obtener un día menos, así que tenga cuidado
Klitos G.
3
Funciona durante los años bisiestos también. mira esto String inputString1 = "28 2 2016"; String inputString2 = "1 3 2016";ans: 2
Rohit Gaikwad
10
Creo que esto funciona correctamente durante los años bisiestos, pero arruina el horario de verano. Si su localidad tiene horario de verano, cada año, hay un día que tiene 23 horas y un día que tiene 25 horas. Esta solución supone incorrectamente que cada día tiene 24 horas. Por lo tanto, da la respuesta incorrecta para cualquier período que comienza durante el horario de verano y termina durante el horario de verano. NO USE ESTA SOLUCIÓN: hay mejores formas.
Dawood ibn Kareem
100

La forma más simple:

public static long getDifferenceDays(Date d1, Date d2) {
    long diff = d2.getTime() - d1.getTime();
    return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
}
bart
fuente
77
Bueno, básicamente esto es lo mismo que la mejor respuesta actual , aunque esta respuesta lo proporciona como una función.
Andrew T.
16
Tenga en cuenta que esto solo cuenta cuando el intervalo de tiempo entre dos fechas es mayor de 24 horas (bastante obvio por el código), por lo tantogetDifferenceDays(11PM, 4 AM nextday) == 0
Redetección
1
Esta implementación toma el último día como hoy. Por ejemplo, si ejecuto el programa con d1 = hoy y d2 = ayer, devuelve 0 días ..
karvoynistas
1
@Nav es porque hay 30 días en junio.
Dawood ibn Kareem
1
Esta respuesta es incorrecta. No trata el horario de verano correctamente. No lo use si desea resultados correctos.
Dawood ibn Kareem
89

En Java 8, puede lograr esto usando LocalDatey DateTimeFormatter. Del Javadoc de LocalDate:

LocalDate es un objeto de fecha y hora inmutable que representa una fecha, a menudo vista como año-mes-día.

Y el patrón se puede construir usando DateTimeFormatter. Aquí está el Javadoc y los caracteres de patrón relevantes que utilicé:

Símbolo - Significado - Presentación - Ejemplos

y - año de la era - año - 2004; 04

M / L - mes del año - número / texto - 7; 07; Jul; Julio; J

d - día del mes - número - 10

Aquí está el ejemplo:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class Java8DateExample {
    public static void main(String[] args) throws IOException {
        final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy");
        final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        final String firstInput = reader.readLine();
        final String secondInput = reader.readLine();
        final LocalDate firstDate = LocalDate.parse(firstInput, formatter);
        final LocalDate secondDate = LocalDate.parse(secondInput, formatter);
        final long days = ChronoUnit.DAYS.between(firstDate, secondDate);
        System.out.println("Days between: " + days);
    }
}

Ejemplo de entrada / salida con el último más reciente:

23 01 1997
27 04 1997
Days between: 94

Con más reciente primero:

27 04 1997
23 01 1997
Days between: -94

Bueno, podrías hacerlo como método de una manera más simple:

public static long betweenDates(Date firstDate, Date secondDate) throws IOException
{
    return ChronoUnit.DAYS.between(firstDate.toInstant(), secondDate.toInstant());
}
mkobit
fuente
44
Excelente ejemplo Esto representa automáticamente el año bisiesto. Si marcó 1991 y 1992 (año bisiesto), se calcula correctamente. ¡Perfecto!
woahguy
Gran uso de la biblioteca estándar.
dieresys
Esta debería ser la respuesta aceptada actual. El uso estándar de la biblioteca y las cuentas de los años bisiestos y el horario de verano no serán un problema.
Pehmolelu
3
Esta es la respuesta actual / moderna (las otras están desactualizadas). También representa el horario de verano (DST). Para usar en Java 6 o 7, obtenga ThreeTen Backport . En el nuevo Android ThreeTenABP .
Ole VV
no tiene en cuenta el horario de verano
Alex
63

La mayoría / todas las respuestas nos causaron problemas cuando llegó el horario de verano. Aquí está nuestra solución de trabajo para todas las fechas, sin usar JodaTime. Utiliza objetos de calendario:

public static int daysBetween(Calendar day1, Calendar day2){
    Calendar dayOne = (Calendar) day1.clone(),
            dayTwo = (Calendar) day2.clone();

    if (dayOne.get(Calendar.YEAR) == dayTwo.get(Calendar.YEAR)) {
        return Math.abs(dayOne.get(Calendar.DAY_OF_YEAR) - dayTwo.get(Calendar.DAY_OF_YEAR));
    } else {
        if (dayTwo.get(Calendar.YEAR) > dayOne.get(Calendar.YEAR)) {
            //swap them
            Calendar temp = dayOne;
            dayOne = dayTwo;
            dayTwo = temp;
        }
        int extraDays = 0;

        int dayOneOriginalYearDays = dayOne.get(Calendar.DAY_OF_YEAR);

        while (dayOne.get(Calendar.YEAR) > dayTwo.get(Calendar.YEAR)) {
            dayOne.add(Calendar.YEAR, -1);
            // getActualMaximum() important for leap years
            extraDays += dayOne.getActualMaximum(Calendar.DAY_OF_YEAR);
        }

        return extraDays - dayTwo.get(Calendar.DAY_OF_YEAR) + dayOneOriginalYearDays ;
    }
}
John Leehey
fuente
maneja muy bien los cambios de horario de verano
Ravi Sanwal
1
Sin embargo, +1 para la respuesta quiere agregar que necesitamos las Calendar dayOne = (Calendar) day1.clone(), dayTwo = (Calendar) day2.clone();líneas ya que aseguran que los valores del calendario original no se anulen. Eliminé estas líneas pensando que eran redundantes y perdí una hora por el hecho de que los valores de mi objeto original se sobrescribían desde el interior de esta función.
Rohan Kandwal
2
No olvide que el valor del mes se basa en 0 en la clase de calendario. calendar.set (2015, 11, 30, 0, 00, 00); en realidad significa 30/12/2015
Dmitry
20

La mejor manera, y se convierte en una Cadena como bonificación;)

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    try {
        //Dates to compare
        String CurrentDate=  "09/24/2015";
        String FinalDate=  "09/26/2015";

        Date date1;
        Date date2;

        SimpleDateFormat dates = new SimpleDateFormat("MM/dd/yyyy");

        //Setting dates
        date1 = dates.parse(CurrentDate);
        date2 = dates.parse(FinalDate);

        //Comparing dates
        long difference = Math.abs(date1.getTime() - date2.getTime());
        long differenceDates = difference / (24 * 60 * 60 * 1000);

        //Convert long to String
        String dayDifference = Long.toString(differenceDates);

        Log.e("HERE","HERE: " + dayDifference);
    }
    catch (Exception exception) {
        Log.e("DIDN'T WORK", "exception " + exception);
    }
}
SoVinceble
fuente
¿Qué es la posibilidad de lanzar una excepción?
Código
Tenga en cuenta que esto no funciona en los años bisiestos. Por ejemplo, del "15/02/2020" al "02/04/2020" son 47 días. Esta lógica surgirá con 46.
user1070304
11

Utilizar:

public int getDifferenceDays(Date d1, Date d2) {
    int daysdiff = 0;
    long diff = d2.getTime() - d1.getTime();
    long diffDays = diff / (24 * 60 * 60 * 1000) + 1;
    daysdiff = (int) diffDays;
    return daysdiff;
}
saidesh kilaru
fuente
¿Esto tiene en cuenta los años bisiestos y el horario de verano?
Max Alexander Hanna
1
@MaxAlexanderHanna representa los años bisiestos correctamente, pero no el horario de verano. Solo da la respuesta correcta cada vez que un período comienza durante el horario de verano, pero termina durante el horario de verano. En todos los demás casos, está apagado por uno.
Dawood ibn Kareem
1
@saidesh_kilaru ¿Qué es el "+ 1"? Creo que deberías eliminarlo.
Alisa
Tuve un problema de que lanzar a INT resultó en 4 y lanzar a flotar resultó en 4.9, por lo que eso no es realmente lo que quería; Quizás no describió con la suficiente claridad los casos para date1 a las 23:59 y date2 a las 00:01 y cuál sería el resultado esperado.
EricG
10

Las bibliotecas de fechas de Java están notoriamente rotas. Aconsejaría usar Joda Time . Se encargará del año bisiesto, la zona horaria, etc.

Ejemplo de trabajo mínimo:

import java.util.Scanner;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class DateTestCase {

    public static void main(String[] args) {

        System.out.print("Insert first date: ");
        Scanner s = new Scanner(System.in);
        String firstdate = s.nextLine();
        System.out.print("Insert second date: ");
        String seconddate = s.nextLine();

        // Formatter
        DateTimeFormatter dateStringFormat = DateTimeFormat
                .forPattern("dd MM yyyy");
        DateTime firstTime = dateStringFormat.parseDateTime(firstdate);
        DateTime secondTime = dateStringFormat.parseDateTime(seconddate);
        int days = Days.daysBetween(new LocalDate(firstTime),
                                    new LocalDate(secondTime)).getDays();
        System.out.println("Days between the two dates " + days);
    }
}
Julien
fuente
44
Esta respuesta podría mejorarse de varias maneras. (a) Especifique la zona horaria en lugar de confiar en el valor predeterminado de la JVM. Entonces, cuando cree ese DateTimeFormatter, agregue una llamada a withZone( DateTimeZone.forID( "Europe/Berlin" ) ). (b) ¿Por qué usar LocalDateen la daysBetweenllamada? Simplemente pase los objetos DateTime (firstTime, secondTime). Para días completos, llame withTimeAtStartOfDays. (c) Usaría nombres de variables en firstDateTimelugar firstTimede evitar la ambigüedad entre los objetos de fecha, hora y fecha-hora. (d) Agregue algunos intentos de captura para manejar la entrada de datos erróneos que no coincide con nuestro formato esperado.
Basil Bourque
5
String dateStart = "01/14/2015 08:29:58";
String dateStop = "01/15/2015 11:31:48";

//HH converts hour in 24 hours format (0-23), day calculation
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");

Date d1 = null;
Date d2 = null;

d1 = format.parse(dateStart);
d2 = format.parse(dateStop);

//in milliseconds
long diff = d2.getTime() - d1.getTime();

long diffSeconds = diff / 1000 % 60;
long diffMinutes = diff / (60 * 1000) % 60;
long diffHours = diff / (60 * 60 * 1000) % 24;
long diffDays = diff / (24 * 60 * 60 * 1000);

System.out.print(diffDays + " days, ");
System.out.print(diffHours + " hours, ");
System.out.print(diffMinutes + " minutes, ");
System.out.print(diffSeconds + " seconds.");
Gautam Viradiya
fuente
1

Cuando ejecuto su programa, ni siquiera me lleva al punto donde puedo ingresar la segunda fecha.

Esto es más simple y menos propenso a errores.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test001 {

    public static void main(String[] args) throws Exception {

        BufferedReader br = null;

        br = new BufferedReader(new InputStreamReader(System.in));
        SimpleDateFormat sdf = new SimpleDateFormat("dd MM yyyy");

        System.out.println("Insert first date : ");
        Date dt1 = sdf.parse(br.readLine().trim());

        System.out.println("Insert second date : ");
        Date dt2 = sdf.parse(br.readLine().trim());

        long diff = dt2.getTime() - dt1.getTime();

        System.out.println("Days: " + diff / 1000L / 60L / 60L / 24L);

        if (br != null) {
            br.close();
        }
    }
}
peter.petrov
fuente
1
// date format, it will be like "2015-01-01"
private static final String DATE_FORMAT = "yyyy-MM-dd";

// convert a string to java.util.Date
public static Date convertStringToJavaDate(String date)
        throws ParseException {
    DateFormat dataFormat = new SimpleDateFormat(DATE_FORMAT);
    return dataFormat.parse(date);
}

// plus days to a date
public static Date plusJavaDays(Date date, int days) {
    // convert to jata-time
    DateTime fromDate = new DateTime(date);
    DateTime toDate = fromDate.plusDays(days);
    // convert back to java.util.Date
    return toDate.toDate();
}

// return a list of dates between the fromDate and toDate
public static List<Date> getDatesBetween(Date fromDate, Date toDate) {
    List<Date> dates = new ArrayList<Date>(0);
    Date date = fromDate;
    while (date.before(toDate) || date.equals(toDate)) {
        dates.add(date);
        date = plusJavaDays(date, 1);
    }
    return dates;
}
Dayong
fuente
0

Podemos hacer uso de la biblioteca Java LocalDate y ChronoUnit. El siguiente código funciona bien. La fecha debe estar en formato aaaa-MM-dd.

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
class Solution {
    public int daysBetweenDates(String date1, String date2) {
        LocalDate dt1 = LocalDate.parse(date1);
        LocalDate dt2= LocalDate.parse(date2);

        long diffDays = ChronoUnit.DAYS.between(dt1, dt2);

        return Math.abs((int)diffDays);
    }
}
Abhijeet Upadhyay
fuente
44
Gracias por querer contribuir. Creo que esta buena sugerencia ya fue presentada en la respuesta por mkobit.
Ole VV