Calcul des jours entre deux dates avec Java

150

Je veux un programme Java qui calcule les jours entre deux dates.

  1. Saisissez la première date (notation allemande; avec des espaces: "jj mm aaaa")
  2. Tapez la deuxième date.
  3. Le programme doit calculer le nombre de jours entre les deux dates.

Comment puis-je inclure les années bissextiles et l'heure d'été?

Mon code:

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);
    }
}
utilisateur3025448
la source
Qu'est-ce qui ne marche pas? Est-ce que ça s'écrase? Est-ce que cela vous donne de faux chiffres?
jens108
Où est la déclaration du tableau: insert1?
Rhys
1
insert1 = eingabe1 en allemand :)
peter.petrov
@ peter.petrov Ah, je vois!
Rhys
Je pense qu'il a un problème avec mmet MM: P
Sage

Réponses:

230

MISE À JOUR: La réponse originale de 2013 est maintenant obsolète car certaines des classes ont été remplacées. La nouvelle façon de faire est d'utiliser les nouvelles 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();
}

Notez que cette solution donnera le nombre réel de 24 heures-jours, et non le nombre de jours civils. Pour ce dernier, utilisez

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

Réponse originale (obsolète à partir de Java 8)

Vous effectuez des conversions avec vos chaînes qui ne sont pas nécessaires. Il y a une SimpleDateFormatclasse pour cela - essayez ceci:

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: Depuis qu'il y a eu des discussions concernant l'exactitude de ce code: il prend en effet en compte les années bissextiles. Cependant, la TimeUnit.DAYS.convertfonction perd en précision car les millisecondes sont converties en jours (voir la documentation liée pour plus d'informations). Si cela pose un problème, diffpeut également être converti à la main:

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

Notez qu'il s'agit d'une floatvaleur, pas nécessairement d'un int.

jens108
la source
40
C'est une mauvaise mise en œuvre qui ne tient pas correctement compte des années bissextiles.
Groovy Ed
3
TimeUnit.DAYS.convert (diff, TimeUnit.MILLISECONDS)); <3
Guihgo
3
@GroovyEd D'après ce que j'ai testé, il semble que ce code n'ait aucun problème avec les années bissextiles. Veuillez noter que TimeUnit.Days.convert () ignorera les unités restantes, par exemple, la conversion de 999 millisecondes en secondes donne 0. Cela signifie que si vous utilisez new Date () comme l'un des objets Date, vous pourriez obtenir un jour de moins, alors faites attention
Klitos G.
3
Cela fonctionne aussi pendant des années bissextiles. vérifier ceci String inputString1 = "28 2 2016"; String inputString2 = "1 3 2016";ans: 2
Rohit Gaikwad
10
Je pense que cela fonctionne correctement pendant les années bissextiles, mais cela gâche l'heure d'été. Si votre région a l'heure d'été, alors chaque année, il y a un jour qui a 23 heures et un jour qui a 25 heures. Cette solution suppose à tort que chaque jour a 24 heures. Il donne donc la mauvaise réponse pour toute période qui commence pendant les heures de non-heure et se termine pendant les heures de lumière du jour. N'UTILISEZ PAS CETTE SOLUTION - il existe de meilleures façons.
Dawood ibn Kareem
100

Manière la plus simple:

public static long getDifferenceDays(Date d1, Date d2) {
    long diff = d2.getTime() - d1.getTime();
    return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
}
bart
la source
7
Eh bien, fondamentalement, c'est la même chose que la meilleure réponse actuelle , bien que cette réponse la fournisse en tant que fonction.
Andrew T.12
16
Notez que ce compte uniquement lorsque l'intervalle de temps entre deux dates est supérieur à 24 heures (assez évident à partir du code), doncgetDifferenceDays(11PM, 4 AM nextday) == 0
ReDetection
1
cette implémentation prend le dernier jour comme aujourd'hui. Par exemple, si j'exécute le programme avec d1 = aujourd'hui et d2 = hier, renvoie 0 jours ..
karvoynistas
1
@Nav c'est parce qu'il y a 30 jours en juin.
Dawood ibn Kareem
1
Cette réponse est incorrecte. Il ne traite pas correctement l'heure d'été. Ne l'utilisez pas si vous voulez des résultats corrects.
Dawood ibn Kareem
89

Dans Java 8, vous pouvez accomplir cela en utilisant LocalDateet DateTimeFormatter. Du Javadoc de LocalDate:

LocalDate est un objet date-heure immuable qui représente une date, souvent considérée comme année-mois-jour.

Et le modèle peut être construit en utilisant DateTimeFormatter. Voici le Javadoc et les caractères de modèle pertinents que j'ai utilisés:

Symbole - Signification - Présentation - Exemples

y - année de l'ère - année - 2004; 04

M / L - mois de l'année - numéro / texte - 7; 07; Juil; Juillet; J

j - jour du mois - nombre - 10

Voici l'exemple:

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

Exemple d'entrée / sortie avec le dernier plus récent:

23 01 1997
27 04 1997
Days between: 94

Avec le plus récent en premier:

27 04 1997
23 01 1997
Days between: -94

Eh bien, vous pouvez le faire en tant que méthode d'une manière plus simple:

public static long betweenDates(Date firstDate, Date secondDate) throws IOException
{
    return ChronoUnit.DAYS.between(firstDate.toInstant(), secondDate.toInstant());
}
mkobit
la source
4
Excellent exemple. Cela tient automatiquement compte de l'année bissextile. Si vous avez coché 1991 et 1992 (année bissextile), il calcule correctement. Parfait!
woahguy
Grande utilisation de la bibliothèque standard.
dieresys
Cela devrait être la réponse actuellement acceptée. L'utilisation standard de la bibliothèque et les comptes des années bissextiles et l'heure d'été ne seront pas un problème.
Pehmolelu
3
C'est la réponse actuelle / moderne (les autres sont obsolètes). Il tient également compte de l'heure d'été (DST). Pour utiliser sur Java 6 ou 7, obtenez ThreeTen Backport . Sur Android ThreeTenABP pas nouveau .
Ole VV
il ne prend pas en compte l'heure d'été
Alex
63

La plupart / toutes les réponses nous ont posé des problèmes lorsque l'heure d'été est arrivée. Voici notre solution de travail pour toutes les dates, sans utiliser JodaTime. Il utilise des objets de calendrier:

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
la source
gère bien les changements d'heure d'été
Ravi Sanwal
1
+1 pour la réponse, cependant, je tiens à ajouter que nous avons besoin des Calendar dayOne = (Calendar) day1.clone(), dayTwo = (Calendar) day2.clone();lignes car elles garantissent que les valeurs de calendrier d'origine ne sont pas remplacées. J'ai supprimé ces lignes les pensant redondantes et j'ai perdu une heure sur le fait que les valeurs de mon objet d'origine étaient écrasées de l'intérieur de cette fonction.
Rohan Kandwal
2
N'oubliez pas que la valeur Month est basée sur 0 dans Calendar Class. calendar.set (2015, 11, 30, 0, 00, 00); signifie en fait 30/12/2015
Dmitry
20

Le meilleur moyen, et il se convertit en une chaîne en 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);
    }
}
SoVinceble
la source
quelle est la possibilité de lancer une exception?
CoDe
Notez que cela ne fonctionne pas les années bissextiles. Par exemple, du "15/02/2020" au "04/02/2020" correspond à 47 jours. Cette logique viendra avec 46.
user1070304
11

Utilisation:

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
la source
Cela tient-il compte des années bissextiles et de l'heure d'été?
Max Alexander Hanna
1
@MaxAlexanderHanna, cela tient compte des années bissextiles correctement, mais pas de l'heure d'été. Il ne donne la bonne réponse que lorsqu'une période commence pendant l'heure d'été, mais se termine pendant l'heure d'été. Dans tous les autres cas, c'est un par un.
Dawood ibn Kareem
1
@saidesh_kilaru Qu'est-ce que le "+ 1"? Je pense que vous devriez le supprimer.
Alisa
J'ai eu un problème avec le fait que le casting en INT aboutissait à 4 et le lancer au flotteur aboutissait à 4,9, donc ce n'est pas vraiment ce que je voulais; Peut-être pas assez clairement décrit les cas pour date1 à 23h59 et date2 à 00h01 et quel serait le résultat attendu.
EricG
10

Les bibliothèques de dates Java sont notoirement cassées. Je conseillerais d'utiliser Joda Time . Il prendra en charge l'année bissextile, le fuseau horaire, etc. pour vous.

Exemple de travail minimal:

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
la source
4
Cette réponse pourrait être améliorée de plusieurs manières. (a) Spécifiez le fuseau horaire plutôt que de vous fier à la valeur par défaut de la JVM. Ainsi, lors de la création de ce DateTimeFormatter, ajoutez un appel à withZone( DateTimeZone.forID( "Europe/Berlin" ) ). (b) Pourquoi utiliser LocalDatedans l' daysBetweenappel? Passez simplement les objets DateTime (firstTime, secondTime). Pour des journées complètes, appelez withTimeAtStartOfDays. (c) J'utiliserais des noms de variables firstDateTimeplutôt que firstTimepour éviter toute ambiguïté entre les objets date, heure et date-heure. (d) Ajoutez des try-catch pour gérer les mauvaises entrées de données qui ne correspondent pas à notre format attendu.
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
la source
1

Lorsque j'exécute votre programme, cela ne m'amène même pas au point où je peux entrer la deuxième date.

C'est plus simple et moins sujet aux erreurs.

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
la source
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
la source
0

Nous pouvons utiliser la bibliothèque java LocalDate et ChronoUnit, le code ci-dessous fonctionne correctement. La date doit être au format aaaa-MM-jj.

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
la source
4
Merci de vouloir contribuer. Je crois que cette bonne suggestion a déjà été présentée dans la réponse de mkobit.
Ole VV