Розрахунок днів між двома датами на 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.