Calcolo dei giorni tra due date con Java


150

Voglio un programma Java che calcoli i giorni tra due date.

  1. Digita la prima data (notazione tedesca; con spazi bianchi: "gg mm aaaa")
  2. Digita la seconda data.
  3. Il programma dovrebbe calcolare il numero di giorni tra le due date.

Come posso includere anni bisestili ed estate?

Il mio codice:

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

Cosa non funziona? Si sta schiantando? Ti sta dando numeri sbagliati?
jens108,

Dov'è la dichiarazione dell'array: insert1?
Rhys,

1
insert1 = eingabe1 in tedesco :)
peter.petrov il

@ peter.petrov Ah, capisco!
Rhys,

Penso che lui sta avendo edizione con mme MM: P
Sage

Risposte:


230

AGGIORNAMENTO: la risposta originale del 2013 è ora obsoleta perché alcune classi sono state sostituite. Il nuovo modo di fare questo è usare le nuove java.timeclassi.

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

Si noti che questa soluzione fornirà il numero di 24 ore effettive, non il numero di giorni di calendario. Per quest'ultimo, utilizzare

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

Risposta originale (non aggiornata a partire da Java 8)

Stai effettuando alcune conversioni con le tue stringhe che non sono necessarie. C'è una SimpleDateFormatclasse per questo - prova questo:

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: Dal momento che ci sono state alcune discussioni sulla correttezza di questo codice: si prende davvero cura degli anni bisestili. Tuttavia, la TimeUnit.DAYS.convertfunzione perde precisione poiché i millisecondi vengono convertiti in giorni (vedere il documento collegato per ulteriori informazioni). Se questo è un problema, diffpuò anche essere convertito a mano:

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

Si noti che questo è un floatvalore, non necessariamente un int.


40
Questa è una cattiva implementazione che non tiene correttamente conto degli anni bisestili.
Groovy Ed,

3
TimeUnit.DAYS.convert (diff, TimeUnit.MILLISECONDS)); <3
Guihgo,

3
@GroovyEd Da quanto ho testato sembra che questo codice non abbia problemi con gli anni bisestili. Si noti che TimeUnit.Days.convert () ignorerà le unità rimanenti, ad esempio convertendo 999 millisecondi in secondi si traduce in 0. Ciò significa che se si utilizza la nuova Data () come uno degli oggetti Data, si potrebbe ottenere un giorno in meno, quindi fare attenzione
Klitos G.

3
Funziona anche per anni bisestili. controlla questo String inputString1 = "28 2 2016"; String inputString2 = "1 3 2016";ans: 2
Rohit Gaikwad,

10
Credo che funzioni correttamente negli anni bisestili, ma rovina l'ora legale. Se la tua località ha l'ora legale, allora ogni anno c'è un giorno che ha 23 ore e un giorno che ha 25 ore. Questa soluzione presuppone erroneamente che ogni giorno abbia 24 ore. Fornisce quindi la risposta errata per qualsiasi periodo che inizia durante l'ora legale e termina durante l'ora legale. NON USARE QUESTA SOLUZIONE - ci sono modi migliori.
Dawood ibn Kareem,

100

Il modo più semplice:

public static long getDifferenceDays(Date d1, Date d2) {
    long diff = d2.getTime() - d1.getTime();
    return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
}

7
Bene, fondamentalmente questo è lo stesso dell'attuale migliore risposta , sebbene questa risposta fornisca come una funzione.
Andrew T.,

16
Si noti che questo conta solo quando l'intervallo di tempo tra due date è maggiore di 24 ore (abbastanza ovvio dal codice), quindigetDifferenceDays(11PM, 4 AM nextday) == 0
ReDetection

1
questa implementazione richiede l'ultimo giorno come oggi. Ad esempio, se
eseguo

1
@Nav è perché ci sono 30 giorni a giugno.
Dawood ibn Kareem,

1
Questa risposta non è corretta Non gestisce correttamente l'ora legale. Non usarlo se vuoi risultati corretti.
Dawood ibn Kareem,

89

In Java 8, è possibile ottenere ciò utilizzando LocalDatee DateTimeFormatter. Dal Javadoc di LocalDate:

LocalDate è un oggetto data-ora immutabile che rappresenta una data, spesso vista come anno-mese-giorno.

E il modello può essere costruito usando DateTimeFormatter. Ecco il Javadoc e i caratteri di pattern pertinenti che ho usato:

Simbolo - Significato - Presentazione - Esempi

y - anno di era - anno - 2004; 04

M / L - mese dell'anno - numero / testo - 7; 07; Jul; Luglio; J

d - giorno del mese - numero - 10

Ecco l'esempio:

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

Esempio di input / output con l'ultimo più recente:

23 01 1997
27 04 1997
Days between: 94

Con prima più recente:

27 04 1997
23 01 1997
Days between: -94

Bene, potresti farlo come metodo in un modo più semplice:

public static long betweenDates(Date firstDate, Date secondDate) throws IOException
{
    return ChronoUnit.DAYS.between(firstDate.toInstant(), secondDate.toInstant());
}

4
Ottimo esempio Ciò rappresenta automaticamente l'anno bisestile. Se hai verificato il 1991 e il 1992 (anno bisestile), viene calcolato correttamente. Perfetto!
woahguy,

Ottimo uso della libreria standard.
Dieresys

Questa dovrebbe essere la risposta attualmente accettata. L'uso della biblioteca standard e gli account degli anni bisestili e dell'ora legale non saranno un problema.
Pehmolelu,

3
Questa è la risposta attuale / moderna (le altre sono obsolete). Conta anche per l'ora legale (DST). Per utilizzare su Java 6 o 7, ottenere ThreeTen Backport . Sul non nuovo Android ThreeTenABP .
Ole VV,

non tiene conto dell'ora legale
Alex

63

La maggior parte / tutte le risposte hanno causato problemi per noi quando è arrivata l'ora legale. Ecco la nostra soluzione di lavoro per tutte le date, senza usare JodaTime. Utilizza gli oggetti del 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 ;
    }
}

gestisce bene gli interruttori dell'ora legale
Ravi Sanwal,

1
+1 per la risposta, tuttavia, desidera aggiungere che sono necessarie le Calendar dayOne = (Calendar) day1.clone(), dayTwo = (Calendar) day2.clone();righe poiché garantiscono che i valori del calendario originale non vengano sovrascritti. Ho eliminato queste righe ritenendole ridondanti e sprecato un'ora per il fatto che i valori del mio oggetto originale venivano sovrascritti all'interno di questa funzione.
Rohan Kandwal,

2
Non dimenticare che il valore del mese è basato su 0 nella classe del calendario. calendar.set (2015, 11, 30, 0, 00, 00); in realtà significa 30/12/2015
Dmitry

20

Il modo migliore e converte in una stringa come bonus;)

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

qual è la possibilità di lanciare un'eccezione?
CoDe

Si noti che questo non funziona negli anni bisestili. Ad esempio, da "15/02/2020" a "02/02/2020" è di 47 giorni. Questa logica verrà fuori con 46.
user1070304

11

Uso:

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

Questo rappresenta anni bisestili e ora legale?
Max Alexander Hanna,

1
@MaxAlexanderHanna rappresenta correttamente gli anni bisestili, ma non l'ora legale. Fornisce la risposta corretta ogni volta che un periodo inizia durante l'ora legale ma termina durante l'ora legale. In tutti gli altri casi, è spento da uno.
Dawood ibn Kareem,

1
@saidesh_kilaru Che cos'è il "+ 1"? Penso che dovresti rimuoverlo.
Alisa,

Ho avuto un problema che il casting su INT ha prodotto 4 e il casting su float ha prodotto 4,9, quindi non è proprio quello che volevo; Forse non abbastanza chiaramente descritto i casi per date1 alle 23:59 e date2 alle 00:01 e quale sarebbe il risultato atteso.
EricG,

10

Le librerie di date Java sono notoriamente rotte. Consiglierei di usare Joda Time . Si occuperà dell'anno bisestile, del fuso orario e così via.

Esempio di lavoro minimo:

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

4
Questa risposta potrebbe essere migliorata in alcuni modi. (a) Specificare il fuso orario piuttosto che fare affidamento sul valore predefinito della JVM. Quindi, quando si crea quel DateTimeFormatter, aggiungere una chiamata a withZone( DateTimeZone.forID( "Europe/Berlin" ) ). (b) Perché usare LocalDatenella daysBetweenchiamata? Basta passare gli oggetti DateTime (firstTime, secondTime). Per giorni interi, chiama withTimeAtStartOfDays. (c) Vorrei usare i nomi delle variabili firstDateTimepiuttosto che firstTimeper evitare l'ambiguità tra oggetti data, ora e data-ora. (d) Aggiungi un po 'di prova per gestire dati errati che non corrispondono al nostro formato previsto.
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.");

1

Quando eseguo il tuo programma, non mi porta nemmeno al punto in cui posso inserire la seconda data.

Questo è più semplice e meno soggetto a errori.

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

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

0

Possiamo usare la libreria java LocalDate e ChronoUnit, il codice sottostante funziona bene. La data deve essere nel formato aaaa-MM-gg.

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

4
Grazie per aver voluto contribuire. Credo che questo buon suggerimento sia già stato presentato nella risposta di mkobit.
Ole VV,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.