Calcular dias entre duas datas com Java

150

Eu quero um programa Java que calcule dias entre duas datas.

  1. Digite a primeira data (notação em alemão; com espaços em branco: "dd mm aaaa")
  2. Digite a segunda data.
  3. O programa deve calcular o número de dias entre as duas datas.

Como posso incluir anos bissextos e verão?

Meu 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);
    }
}
user3025448
fonte
O que não funciona? Está falhando? Está lhe dando números errados?
jens108
Onde está a declaração da matriz: insert1?
Rhys #
1
insert1 = eingabe1 em alemão :)
peter.petrov 23/11
@ peter.petrov Ah, entendo!
21413 Rhys
Eu acho que ele está tendo problemas com mme MM: P
Sábio

Respostas:

229

ATUALIZAÇÃO: a resposta original de 2013 agora está desatualizada porque algumas das classes foram substituídas. A nova maneira de fazer isso é usar as novas java.timeclasses.

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();
}

Observe que esta solução fornecerá o número real de 24 horas por dia, não o número de dias corridos. Para este último, use

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

Resposta original (desatualizada a partir do Java 8)

Você está fazendo algumas conversões com suas cordas que não são necessárias. Há uma SimpleDateFormatclasse para isso - tente o seguinte:

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();
}

EDIT: Como houve algumas discussões sobre a correção desse código: ele realmente cuida dos anos bissextos. No entanto, a TimeUnit.DAYS.convertfunção perde precisão, pois os milissegundos são convertidos em dias (consulte o documento vinculado para obter mais informações). Se isso for um problema, difftambém pode ser convertido manualmente:

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

Observe que este é um floatvalor, não necessariamente um int.

jens108
fonte
40
Esta é uma implementação ruim que não conta anos bissextos corretamente.
Groovy Ed
3
TimeUnit.DAYS.convert (diff, TimeUnit.MILLISECONDS)); <3
Guihgo 03/01
3
@GroovyEd Pelo que testei, parece que esse código não tem problemas com anos bissextos. Observe que TimeUnit.Days.convert () ignorará as unidades restantes, por exemplo, converter 999 milissegundos em segundos resulta em 0. Isso significa que se você usar new Date () como um dos objetos Date, poderá ficar menos um dia, portanto, tome cuidado
Klitos G. 03/06
3
Também funciona por anos bissextos. Verifique esta String inputString1 = "28 2 2016"; String inputString2 = "1 3 2016";ans: 2
Rohit Gaikwad 29/11
10
Acredito que isso funcione corretamente por anos bissextos, mas atrapalha o horário de verão. Se o seu código do idioma tiver horário de verão, todo ano, haverá um dia com 23 horas e um dia com 25 horas. Esta solução assume incorretamente que todos os dias têm 24 horas. Portanto, fornece a resposta errada para qualquer período que comece durante o horário de verão e termina durante o horário de verão. NÃO USE ESTA SOLUÇÃO - existem maneiras melhores.
Dawood ibn Kareem
100

Maneira mais simples:

public static long getDifferenceDays(Date d1, Date d2) {
    long diff = d2.getTime() - d1.getTime();
    return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
}
bart
fonte
7
Bem, basicamente isso é o mesmo que a melhor resposta atual , embora essa resposta a forneça como uma função.
Andrew T.
16
Observe que isso conta apenas quando o intervalo de tempo entre duas datas é maior que 24 horas (bastante óbvio no código), portantogetDifferenceDays(11PM, 4 AM nextday) == 0
ReDetection
1
essa implementação leva o último dia como hoje. Por exemplo, se eu executar o programa com d1 = hoje, e d2 = ontem, retorna 0 dias ..
karvoynistas
1
@ Nav é porque há 30 dias em junho.
Dawood ibn Kareem
1
Esta resposta está incorreta. Não lida corretamente com o horário de verão. Não use se você deseja resultados corretos.
Dawood ibn Kareem
89

No Java 8, você pode fazer isso usando LocalDatee DateTimeFormatter. Do Javadoc de LocalDate:

LocalDate é um objeto de data e hora imutável que representa uma data, geralmente vista como ano-mês-dia.

E o padrão pode ser construído usando DateTimeFormatter. Aqui está o Javadoc e os caracteres padrão relevantes que eu usei:

Símbolo - Significado - Apresentação - Exemplos

y - ano da era - ano - 2004; 04

M / L - mês do ano - número / texto - 7; 07; Jul; Julho; J

d - dia do mês - número - 10

Aqui está o exemplo:

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);
    }
}

Exemplo de entrada / saída com o último mais recente:

23 01 1997
27 04 1997
Days between: 94

Com o mais recente primeiro:

27 04 1997
23 01 1997
Days between: -94

Bem, você poderia fazer isso como um método de uma maneira mais simples:

public static long betweenDates(Date firstDate, Date secondDate) throws IOException
{
    return ChronoUnit.DAYS.between(firstDate.toInstant(), secondDate.toInstant());
}
mkobit
fonte
4
Excelente exemplo. Isso representa automaticamente o ano bissexto. Se você verificou 1991 e 1992 (ano bissexto), ele calcula corretamente. Perfeito!
Woahguy 29/03/16
Ótimo uso da biblioteca padrão.
dieresys
Essa deve ser a resposta atualmente aceita. O uso padrão da biblioteca e contas por anos bissextos e horário de verão não serão um problema.
Pehmolelu 29/08
3
Esta é a resposta atual / moderna (as outras estão desatualizadas). Também é responsável pelo horário de verão (DST). Para usar no Java 6 ou 7, obtenha o ThreeTen Backport . No novo Android ThreeTenABP .
Ole VV
ele não leva em conta o horário de verão
Alex
63

A maioria das respostas causou problemas para nós quando o horário de verão chegou. Aqui está a nossa solução de trabalho para todas as datas, sem usar o JodaTime. Utiliza objetos de calendário:

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
fonte
alças Daylight economizando tempo interruptores bem
Ravi Sanwal
1
+1 para a resposta, no entanto, deseja adicionar que precisamos das Calendar dayOne = (Calendar) day1.clone(), dayTwo = (Calendar) day2.clone();linhas, pois elas garantem que os valores originais da agenda não sejam substituídos. Excluí essas linhas, considerando-as redundantes e perdi uma hora com o fato de que os valores do meu objeto original estavam sendo substituídos por dentro dessa função.
Rohan Kandwal 17/08/2015
2
Não se esqueça que o valor do mês é baseado em 0 na classe Calendar. calendar.set (2015, 11, 30, 0, 00, 00); realmente significa 30/12/2015
Dmitry
20

A melhor maneira, e ele se converte em uma String como bônus;)

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
fonte
qual é a possibilidade de lançar uma exceção?
CoDe
Observe que isso não funciona em anos bissextos. Por exemplo, de "15/02/2020" a "04/02/2020" são 47 dias. Essa lógica terá 46.
user1070304 11/03
11

Usar:

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
fonte
Isso explica anos bissextos e horário de verão?
Max Alexander Hanna
1
@MaxAlexanderHanna é responsável por anos bissextos corretamente, mas não pelo horário de verão. Ele fornece a resposta correta apenas quando um período começa durante o horário de verão, mas termina durante o horário de verão. Em todos os outros casos, é desativado por um.
Dawood ibn Kareem
1
@saidesh_kilaru O que é o "+ 1"? Eu acho que você deveria removê-lo.
Alisa #
Eu tive um problema que a conversão para a INT resultou em 4 e a conversão para flutuante resultou em 4,9, então não era exatamente isso que eu queria; Talvez não seja suficientemente claro o que descreveu os casos para date1 às 23:59 e date2 às 00:01 e qual seria o resultado esperado.
EricG
10

As bibliotecas de datas Java são notoriamente quebradas. Eu recomendaria usar o Joda Time . Ele cuidará do ano bissexto, do fuso horário e assim por diante.

Exemplo de trabalho 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
fonte
4
Esta resposta pode ser melhorada de algumas maneiras. (a) Especifique o fuso horário em vez de confiar no padrão da JVM. Portanto, ao criar esse DateTimeFormatter, adicione uma chamada a withZone( DateTimeZone.forID( "Europe/Berlin" ) ). (b) Por que usar LocalDatena daysBetweenchamada? Apenas passe objetos DateTime (firstTime, secondTime). Por dias inteiros, ligue withTimeAtStartOfDays. (c) Eu usaria nomes de variáveis ​​em firstDateTimevez firstTimede evitar ambiguidade entre objetos de data, hora e data e hora. (d) Adicione alguma tentativa de captura para manipular dados incorretos que não correspondam ao formato esperado.
Basil Bourque 14/03
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
fonte
1

Quando executo seu programa, ele nem chega ao ponto em que posso inserir a segunda data.

Isso é mais simples e menos propenso a erros.

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
fonte
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
fonte
0

Podemos fazer uso das bibliotecas java LocalDate e ChronoUnit. O código abaixo está funcionando bem. A data deve estar no 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
fonte
4
Obrigado por querer contribuir. Acredito que essa boa sugestão já foi apresentada na resposta por mkobit.
Ole VV