Calcular dias entre duas datas no Java 8

250

Eu sei que há muitas perguntas sobre SO sobre como obter, mas eu quero e exemplo usando a nova API do Java 8 Date. Eu também conheço a biblioteca JodaTime, mas quero uma maneira de trabalhar sem bibliotecas externas.

A função precisa reclamar com estas restrições:

  1. Evitar erros a partir da data de economia
  2. Entrada são dois objetos de Data (sem hora, eu sei localdatetime, mas preciso fazer com instâncias de data)
Marcos
fonte
2
Algo assim por exemplo ?
MadProgrammer
@MadProgrammer Não é verdade - Duração não é o mais adequado para fazer isso ...
assylias
@assylias Bem, é melhor do que o que o OP teve
MadProgrammer
@assylias Então, o que é?
MadProgrammer
16
@MadProgrammer DAYS.between(localDate1, localDate2).
Assilias

Respostas:

434

Se você deseja dias lógicos de calendário , use o DAYS.between()método de java.time.temporal.ChronoUnit:

LocalDate dateBefore;
LocalDate dateAfter;
long daysBetween = DAYS.between(dateBefore, dateAfter);

Se você quiser dias literais de 24 horas (uma duração ), poderá usar a Durationclasse:

LocalDate today = LocalDate.now()
LocalDate yesterday = today.minusDays(1);
// Duration oneDay = Duration.between(today, yesterday); // throws an exception
Duration.between(today.atStartOfDay(), yesterday.atStartOfDay()).toDays() // another option

Para mais informações, consulte este documento .

sintagma
fonte
15
Isso gera uma exceção, porque o método Duration.between requer objetos temporais capazes de suportar a unidade SECONDS . Em vez disso, tente Duration.between(today.atTime(0, 0), yesterday.atTime(0, 0)).toDays().
VGR
5
Em vez de today.atTime(0, 0)você pode fazer today.atStartOfDay().
eee
5
@REACHUS Talvez o -1 tenha sido um pouco duro porque o código que você propõe funciona, mas o Duration deve medir "quantidades de tempo baseadas no tempo". Existe uma maneira integrada de medir um número de dias que não requer conversão de data para data e hora.
Assilias
A melhor resposta para o LocalDate é a resposta de @Sunil B abaixo:ChronoUnit.DAYS.between(firstDate, secondDate)
Lappro
@ Lappro por que é melhor? Ele usa o mesmo método da minha resposta
syntagma
130

Com base nos comentários do VGR, aqui está o que você pode usar:

ChronoUnit.DAYS.between(firstDate, secondDate)
Sunil B
fonte
38

Você pode usar until():

LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4);
LocalDate christmas = LocalDate.of(2014, Month.DECEMBER, 25);

System.out.println("Until christmas: " + independenceDay.until(christmas));
System.out.println("Until christmas (with crono): " + independenceDay.until(christmas, ChronoUnit.DAYS));
nazar_art
fonte
4
O problema que acabei de encontrar com a primeira versão untilé que ele retorna um objeto Period . Isso retornará vários anos / meses / dias entre as duas datas, não o número real de dias. E getDays () no Período retorna apenas a parte dos dias (sem levar em consideração o número de anos ou meses), em vez do número total de dias. A segunda versão funciona exatamente como desejado para obter um número de dias entre duas datas.
28718 Justin M.
Existe uma alternativa completa para isso? Desde que precisa SDK para Android 26 e acima
ralphgabb
12

Você pode usar DAYS.betweendejava.time.temporal.ChronoUnit

por exemplo

import java.time.temporal.ChronoUnit;

public long getDaysCountBetweenDates(LocalDate dateBefore, LocalDate dateAfter) {
    return DAYS.between(dateBefore, dateAfter);
}
Piotr Fryga
fonte
10

Se startDate e endDate forem instância de java.util.Date

Podemos usar o método between () do ChronoUnit enum:

public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) {
    //..
}

ChronoUnit.DAYS contam dias que completaram 24 horas .

import java.time.temporal.ChronoUnit;

ChronoUnit.DAYS.between(startDate.toInstant(), endDate.toInstant());

//OR 

ChronoUnit.DAYS.between(Instant.ofEpochMilli(startDate.getTime()), Instant.ofEpochMilli(endDate.getTime()));
Pawan
fonte
8

Use os DAYS no enum java.time.temporal.ChronoUnit . Abaixo está o código de exemplo:

Saída: * Número de dias entre a data de início: 01/03/2015 e a data de término: 03-03-2016 é ==> 368. ** Número de dias entre a data de início: 03-03-2016 e a data de término: 01/03/2015 é ==> -368 *

package com.bitiknow.date;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

/**
 * 
 * @author pradeep
 *
 */
public class LocalDateTimeTry {
    public static void main(String[] args) {

        // Date in String format.
        String dateString = "2015-03-01";

        // Converting date to Java8 Local date
        LocalDate startDate = LocalDate.parse(dateString);
        LocalDate endtDate = LocalDate.now();
        // Range = End date - Start date
        Long range = ChronoUnit.DAYS.between(startDate, endtDate);
        System.out.println("Number of days between the start date : " + dateString + " and end date : " + endtDate
                + " is  ==> " + range);

        range = ChronoUnit.DAYS.between(endtDate, startDate);
        System.out.println("Number of days between the start date : " + endtDate + " and end date : " + dateString
                + " is  ==> " + range);

    }

}
Pradeep Padmarajaiah
fonte
8

Todo mundo está dizendo para usar o ChronoUnit.DAYS.between, mas isso apenas delega para outro método que você poderia chamar. Então você também pode fazer firstDate.until(secondDate, ChronoUnit.DAYS).

Os documentos de ambos mencionam as duas abordagens e dizem para usar a que for mais legível.

nafg
fonte
FWIW ... Não sei por que os dois existem. Há momentos em que um é mais legível e momentos em que o outro é? Quando por que?
Nafg
5

Aqui está:

public class DemoDate {
    public static void main(String[] args) {
        LocalDate today = LocalDate.now();
        System.out.println("Current date: " + today);

        //add 1 month to the current date
        LocalDate date2 = today.plus(1, ChronoUnit.MONTHS);
        System.out.println("Next month: " + date2);

        // Put latest date 1st and old date 2nd in 'between' method to get -ve date difference
        long daysNegative = ChronoUnit.DAYS.between(date2, today);
        System.out.println("Days : "+daysNegative);

        // Put old date 1st and new date 2nd in 'between' method to get +ve date difference
        long datePositive = ChronoUnit.DAYS.between(today, date2);
        System.out.println("Days : "+datePositive);
    }
}
Pra_A
fonte
5

Obtenha o número de dias antes do Natal do dia atual, tente isso

System.out.println(ChronoUnit.DAYS.between(LocalDate.now(),LocalDate.of(Year.now().getValue(), Month.DECEMBER, 25)));
survivor_27
fonte
3

Se o objetivo é apenas obter a diferença em dias e, como as respostas acima mencionam os métodos delegados, gostaria de salientar que uma vez também pode simplesmente usar:

public long daysInBetween(java.time.LocalDate startDate, java.time.LocalDate endDate) {
  // Check for null values here

  return endDate.toEpochDay() - startDate.toEpochDay();
}
levenshtein
fonte
1
Ao cair na armadilha, use 'Period.between (date1, date2) .getDays ()' sem perceber que você perde os meses e anos da diferença.
MrSmith42
2

obter dias entre duas datas é uma instância de java.util.Date

public static long daysBetweenTwoDates(Date dateFrom, Date dateTo) {
            return DAYS.between(Instant.ofEpochMilli(dateFrom.getTime()), Instant.ofEpochMilli(dateTo.getTime()));
        }
Mohamed.Abdo
fonte
1

Eu sei que esta pergunta é para Java 8, mas com o Java 9 você pode usar:

public static List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate) {
    return startDate.datesUntil(endDate)
      .collect(Collectors.toList());
}
Xxtreem
fonte
0

Use a classe ou o método que melhor atenda às suas necessidades:

  • a classe Duration ,
  • Classe período
  • ou o método ChronoUnit.between .

A Duration mede uma quantidade de tempo usando valores baseados em tempo (segundos, nanossegundos).

Um Período usa valores baseados em data (anos, meses, dias).

O método ChronoUnit.between é útil quando você deseja medir uma quantidade de tempo em uma única unidade de tempo, como dias ou segundos.

https://docs.oracle.com/javase/tutorial/datetime/iso/period.html

Samuel
fonte