Розрахунок днів між двома датами на Java


150

Я хочу, щоб програма Java розраховувала дні між двома датами.

  1. Введіть першу дату (німецька позначка; пробіли: "dd mm yyyy")
  2. Введіть другу дату.
  3. Програма повинна обчислити кількість днів між двома датами.

Як я можу включати високосні роки та літній час?

Мій код:

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

Що не працює? Це збої? Чи дає вам неправильні цифри?
jens108

Де декларація масиву: insert1?
Rhys

1
insert1 = eingabe1 німецькою мовою :)
peter.petrov

@ peter.petrov Ах, бачу!
Rhys

Я думаю , що він має проблеми з mmі MM: P
Sage

Відповіді:


230

ОНОВЛЕННЯ: Первісна відповідь 2013 року застаріла, оскільки деякі класи були замінені. Новим способом цього є використання нових java.timeкласів.

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

Зауважте, що це рішення дасть кількість фактичних 24 годин-днів, а не кількість календарних днів. Для останнього використовуйте

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

Оригінальна відповідь (застаріла на Java 8)

Ви робите кілька перетворень за допомогою рядків, які не потрібні. Для цього є SimpleDateFormatклас - спробуйте:

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: Оскільки були дискусії щодо правильності цього коду: він дійсно піклується про високосні роки. Однак TimeUnit.DAYS.convertфункція втрачає точність, оскільки мілісекунди перетворюються на дні (для отримання додаткової інформації див. Пов'язаний документ). Якщо це проблема, diffтакож можна перетворити вручну:

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

Зауважте, що це floatзначення, не обов'язково а int.


40
Це погана реалізація, яка не враховує високосні роки.
Groovy Ed

3
TimeUnit.DAYS.convert (розл., TimeUnit.MILLISECONDS)); <3
Guihgo

3
@GroovyEd З того, що я перевірив, схоже, що цей код не має проблем у високосні роки. Зверніть увагу, що TimeUnit.Days.convert () ігнорує залишилися одиниці, наприклад, перетворення 999 мілісекунд в секунди призводить до 0. Це означає, що якщо ви використовуєте нову Date () як один з об'єктів Date, ви можете отримати на один день менше, тому будьте обережні
Клітос Г.

3
Це працює і в високосні роки. перевірити це String inputString1 = "28 2 2016"; String inputString2 = "1 3 2016";: 2
Rohit Gaikwad

10
Я вважаю, що це працює правильно у високосні роки, але це заважає літньому часу. Якщо у вашому регіоні є час на літній час, то щороку є один день, який має 23 години, і один день, який має 25 годин. Це рішення неправильно передбачає, що кожен день має 24 години. Таким чином, він дає неправильну відповідь за будь-який період, який починається під час денного і закінчується під час літнього часу. НЕ ВИКОРИСТОВУЙТЕ ЦЕ РІШЕННЯ - є кращі способи.
Давуд ібн Карім

100

Найпростіший спосіб:

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

7
Ну, в основному це те саме, що поточна найкраща відповідь , хоча ця відповідь забезпечує це як функцію.
Андрій Т.

16
Зауважимо, що це враховується лише тоді, коли інтервал часу між двома датами перевищує 24 години (досить очевидно з коду), таким чиномgetDifferenceDays(11PM, 4 AM nextday) == 0
ReDetection

1
ця реалізація займає останній день як сьогодні. Наприклад, якщо я запускаю програму з d1 = сьогодні, і d2 = вчора, повертається 0 днів ..
karvoynistas

1
@Nav це тому, що в червні 30 днів.
Dawood ibn Kareem

1
Ця відповідь невірна. Він не справляється з літнім часом. Не використовуйте його, якщо хочете правильних результатів.
Dawood ibn Kareem

89

У Java 8 це можна зробити за допомогою LocalDateі DateTimeFormatter. З Javadoc з LocalDate:

LocalDate - це незмінний об'єкт дати та часу, який представляє дату, часто розглядається як рік-місяць-день.

І візерунок можна побудувати за допомогою DateTimeFormatter. Ось Javadoc та відповідні символи візерунка, які я використав:

Символ - Значення - Презентація - Приклади

y - рік епохи - рік - 2004; 04

M / L - місяць року - число / текст - 7; 07; Липень; Липень; J

d - день місяця - число - 10

Ось приклад:

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

Приклад введення / виведення з останніми останніми:

23 01 1997
27 04 1997
Days between: 94

З останнім першим:

27 04 1997
23 01 1997
Days between: -94

Ну, ви могли це зробити як простіший спосіб:

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

4
Відмінний приклад. Це автоматично враховує високосний рік. Якщо ви перевірили 1991 та 1992 роки (високосний рік), він обчислює правильно. Ідеально!
woahguy

Велике використання стандартної бібліотеки.
дірезі

Це має бути поточно прийнята відповідь. Стандартне використання бібліотек та облікових записів за високосні роки та заощадження літнього часу не буде проблемою.
Pehmolelu

3
Це поточна / сучасна відповідь (інші застаріли). Він також враховує літній час (DST). Щоб використовувати на Java 6 або 7, отримайте ThreeTen Backport . На не новому Android ThreeTenABP .
Оле ВВ

він не враховує літній час
Алекс

63

Більшість / усі відповіді викликали у нас проблеми, коли з’явився літній час. Ось наше робоче рішення на всі дати, без використання JodaTime. Він використовує об’єкти календаря:

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

обробляє перехід на літній час прекрасно
Раві Санваль

1
+1 для відповіді хочемо додати, що нам потрібні Calendar dayOne = (Calendar) day1.clone(), dayTwo = (Calendar) day2.clone();рядки, оскільки вони гарантують, що вихідні значення календаря не будуть перевершені. Я видалив ці рядки, вважаючи їх зайвими і витратив годину на те, що значення мого оригінального об'єкта перезаписуються зсередини цієї функції.
Рохан Кандвал

2
Не забувайте, що значення "Місяць" в класі "Календар" базується на 0. Calendar.set (2015, 11, 30, 0, 00, 00); фактично означає 30/12/2015
Дмитро

20

Найкращий спосіб, і він перетворюється на String як бонус;)

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

яка можливість викидання виключення?
CoDe

Зауважте, що це не працює в високосні роки. Наприклад, від "15.02.2020" до "02.02.2020" проходить 47 днів. Ця логіка придумає 46.
user1070304

11

Використання:

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

Це враховує високосні роки та економію денного світла?
Макс Олександр Ганна

1
@MaxAlexanderHanna правильно приділяє високосні роки, але не економію денного світла. Він дає правильну відповідь лише коли період починається під час не денного часу, але закінчується під час літнього часу. У всіх інших випадках він вимикається одним.
Dawood ibn Kareem

1
@saidesh_kilaru Що таке "+ 1"? Я думаю, ви повинні її зняти.
Аліса

У мене виникла проблема, що кастинг на INT привів до 4, а кастинг до плаваючого - 4,9, так що насправді те, чого я хотів; Можливо, недостатньо чітко описані випадки щодо дати1 о 23:59 та дати2 о 00:01 та яким би був очікуваний результат.
EricG

10

Бібліотеки дат Java суттєво порушені. Я б радив використовувати Joda Time . Він піклується про високосний рік, часовий пояс тощо.

Мінімальний робочий приклад:

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
Цю відповідь можна було б покращити кількома способами. (a) Вкажіть часовий пояс, а не покладайтеся на замовчування JVM. Отже, коли створюєте DateTimeFormatter, додайте виклик до withZone( DateTimeZone.forID( "Europe/Berlin" ) ). (Б) Навіщо використовувати LocalDateв daysBetweenвиклику? Просто передайте об'єкти DateTime (firstTime, secondTime). Цілі дні телефонуйте withTimeAtStartOfDays. (c) Я б скористався іменами змінних, firstDateTimeа не firstTimeщоб уникнути неоднозначності між об'єктами дати, часу та дати. (d) Додайте кілька спроб лову, щоб обробити невдалі введення даних, які не відповідають нашому очікуваному формату.
Василь Бурк

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

Коли я запускаю вашу програму, це навіть не доводить мене до того, коли я можу ввести друге побачення.

Це простіше і менш схильні до помилок.

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

Ми можемо скористатися явами LocalDate та ChronoUnit, нижче код добре працює. Дата повинна бути у форматі рр-р-ММ-дд.

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
Дякуємо, що хочете зробити свій внесок. Я вважаю, що ця гарна пропозиція вже була представлена ​​у відповіді mkobit.
Оле ВВ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.