Tính ngày giữa hai ngày với Java


150

Tôi muốn một chương trình Java tính toán ngày giữa hai ngày.

  1. Nhập ngày đầu tiên (ký hiệu tiếng Đức; với khoảng trắng: "dd mm yyyy")
  2. Nhập ngày thứ hai.
  3. Chương trình sẽ tính toán số ngày giữa hai ngày.

Làm thế nào tôi có thể bao gồm năm nhuận và mùa hè?

Mã của tôi:

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

Điều gì không làm việc? Có phải nó bị rơi không? Là nó cho bạn số sai?
jens108

Đâu là khai báo của mảng: insert1?
Rhys

1
insert1 = eingabe1 bằng tiếng Đức :)
peter.petrov

@ peter.petrov À, tôi hiểu rồi!
Rhys

Tôi nghĩ anh ta có vấn đề với mmMM: P
Sage

Câu trả lời:


229

CẬP NHẬT: Câu trả lời ban đầu từ năm 2013 hiện đã lỗi thời vì một số lớp đã được thay thế. Cách mới để làm điều này là sử dụng các java.timelớp mới .

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

Lưu ý rằng giải pháp này sẽ đưa ra số ngày thực tế 24 giờ, không phải số ngày theo lịch. Đối với cái sau, sử dụng

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

Câu trả lời gốc (lỗi thời kể từ Java 8)

Bạn đang thực hiện một số chuyển đổi với Chuỗi không cần thiết. Có một SimpleDateFormatlớp học cho nó - hãy thử điều này:

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: Vì đã có một số cuộc thảo luận liên quan đến tính chính xác của mã này: nó thực sự quan tâm đến những năm nhuận. Tuy nhiên, TimeUnit.DAYS.converthàm mất độ chính xác vì mili giây được chuyển đổi thành ngày (xem tài liệu được liên kết để biết thêm thông tin). Nếu đây là một vấn đề, diffcũng có thể được chuyển đổi bằng tay:

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

Lưu ý rằng đây là một floatgiá trị, không nhất thiết phải là một int.


40
Đây là một triển khai xấu mà tài khoản không có năm nhuận đúng.
Groovy Ed

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

3
@GroovyEd Từ những gì tôi đã kiểm tra, có vẻ như mã này không có vấn đề gì với năm nhuận. Vui lòng lưu ý rằng TimeUnit.
Klitos G.

3
Nó hoạt động cho năm nhuận quá. kiểm tra String inputString1 = "28 2 2016"; String inputString2 = "1 3 2016";ans này : 2
Rohit Gaikwad

10
Tôi tin rằng điều này hoạt động chính xác trong những năm nhuận, nhưng nó làm rối tung thời gian tiết kiệm ánh sáng ban ngày. Nếu địa phương của bạn có thời gian tiết kiệm ánh sáng ban ngày, thì mỗi năm, có một ngày có 23 giờ và một ngày có 25 giờ. Giải pháp này giả định không chính xác rằng mỗi ngày có 24 giờ. Do đó, nó đưa ra câu trả lời sai cho bất kỳ khoảng thời gian nào bắt đầu trong tiết kiệm không phải ban ngày và kết thúc trong tiết kiệm ánh sáng ban ngày. KHÔNG SỬ DỤNG GIẢI PHÁP NÀY - có nhiều cách tốt hơn.
Dawood ibn Kareem

100

Cách đơn giản nhất:

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

7
Vâng, về cơ bản, đây là giống như câu trả lời tốt nhất hiện tại , mặc dù câu trả lời này cung cấp nó như là một chức năng.
Andrew T.

16
Lưu ý, điều này chỉ được tính khi khoảng thời gian giữa hai ngày lớn hơn 24 giờ (khá rõ ràng từ mã), do đógetDifferenceDays(11PM, 4 AM nextday) == 0
ReDetection

1
việc thực hiện này mất ngày cuối cùng như ngày hôm nay. Chẳng hạn, nếu tôi chạy chương trình với d1 = hôm nay và d2 = hôm qua, trả về 0 ngày ..
karvoynistas

1
@Nav đó là vì có 30 ngày trong tháng Sáu.
Dawood ibn Kareem

1
Câu trả lời này không chính xác. Nó không đối phó với thời gian tiết kiệm ánh sáng ban ngày một cách chính xác. Đừng sử dụng nó nếu bạn muốn kết quả chính xác.
Dawood ibn Kareem

89

Trong Java 8, bạn có thể thực hiện điều này bằng cách sử dụng LocalDateDateTimeFormatter. Từ Javadoc của LocalDate:

LocalDate là một đối tượng ngày giờ bất biến đại diện cho một ngày, thường được xem là ngày tháng năm.

Và mô hình có thể được xây dựng bằng cách sử dụng DateTimeFormatter. Đây là Javadoc và các ký tự mẫu có liên quan mà tôi đã sử dụng:

Biểu tượng - Ý nghĩa - Trình bày - Ví dụ

y - năm của thời đại - năm - 2004; 04

M / L - tháng của năm - số / văn bản - 7; 07; Tháng 7; Tháng 7; J

d - ngày tháng - số - 10

Dưới đây là ví dụ:

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

Ví dụ đầu vào / đầu ra với lần gần đây nhất:

23 01 1997
27 04 1997
Days between: 94

Với lần đầu tiên gần đây hơn:

27 04 1997
23 01 1997
Days between: -94

Chà, bạn có thể làm nó như một phương pháp theo cách đơn giản hơn:

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

4
Ví dụ tuyệt vời. Điều này tự động chiếm năm nhuận. Nếu bạn kiểm tra năm 1991 và 1992 (năm nhuận), nó sẽ tính toán chính xác. Hoàn hảo!
woahguy

Sử dụng tuyệt vời của thư viện tiêu chuẩn.
dieresys

Đây phải là câu trả lời được chấp nhận hiện tại. Sử dụng thư viện tiêu chuẩn và tài khoản cho năm nhuận và tiết kiệm ánh sáng ban ngày sẽ không là vấn đề.
Pehmolelu

3
Đây là câu trả lời hiện tại / hiện đại (những câu hỏi khác đã lỗi thời). Nó cũng chiếm thời gian mùa hè (DST). Để sử dụng trên Java 6 hoặc 7, hãy lấy ThreeTen Backport . Trên Android ThreeTenABP không mới .
Ole VV

nó không tính đến thời gian tiết kiệm ánh sáng ban ngày
Alex

63

Hầu hết / tất cả các câu trả lời gây ra vấn đề cho chúng tôi khi thời gian tiết kiệm ánh sáng ban ngày xuất hiện. Đây là giải pháp làm việc của chúng tôi cho tất cả các ngày, mà không cần sử dụng JodaTime. Nó sử dụng các đối tượng lịch:

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

xử lý các công tắc tiết kiệm thời gian ban ngày độc đáo
Ravi Sanwal

1
Tuy nhiên, +1 cho câu trả lời muốn thêm rằng chúng tôi cần các Calendar dayOne = (Calendar) day1.clone(), dayTwo = (Calendar) day2.clone();dòng vì chúng đảm bảo rằng các giá trị lịch ban đầu không bị ghi đè. Tôi đã xóa những dòng này vì nghĩ chúng dư thừa và lãng phí một giờ vì thực tế là các giá trị của đối tượng ban đầu của tôi đã bị ghi đè từ bên trong hàm này.
Rohan Kandwal 17/08/2015

2
Đừng quên rằng giá trị Tháng là 0 dựa trên Lớp Lịch. calendar.set (2015, 11, 30, 0, 00, 00); thực sự có nghĩa là 30/12/2015
Dmitry

20

Cách tốt nhất và nó chuyển đổi thành Chuỗi dưới dạng phần thưởng;)

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

khả năng ném ngoại lệ là gì?
CoDe

Lưu ý rằng điều này không hoạt động trong năm nhuận. Ví dụ: từ "02/15/2020" đến "04/02/2020" là 47 ngày. Logic này sẽ xuất hiện với 46.
user1070304

11

Sử dụng:

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

Liệu tài khoản này cho năm nhuận và tiết kiệm ánh sáng ban ngày?
Max Alexander Hanna

1
@MaxAlexanderHanna nó chiếm đúng năm nhuận, nhưng không tiết kiệm ánh sáng ban ngày. Nó chỉ đưa ra câu trả lời chính xác bất cứ khi nào một khoảng thời gian bắt đầu trong thời gian tiết kiệm không phải ban ngày nhưng kết thúc trong tiết kiệm ánh sáng ban ngày. Trong tất cả các trường hợp khác, nó tắt bởi một.
Dawood ibn Kareem

1
@saidesh_kilaru "+ 1" là gì? Tôi nghĩ bạn nên loại bỏ nó.
Alisa

Tôi đã gặp sự cố khi truyền vào INT kết quả là 4 và chuyển sang float kết quả là 4.9, vì vậy đó không thực sự là điều tôi muốn; Có lẽ không đủ rõ ràng mô tả các trường hợp cho date1 lúc 23:59 và date2 lúc 00:01 và kết quả mong đợi sẽ là gì.
EricG

10

Thư viện ngày Java nổi tiếng là bị phá vỡ. Tôi sẽ khuyên bạn nên sử dụng Joda Time . Nó sẽ chăm sóc năm nhuận, múi giờ và như vậy cho bạn.

Ví dụ làm việc tối thiểu:

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
Câu trả lời này có thể được cải thiện theo một số cách. (a) Chỉ định múi giờ thay vì dựa vào mặc định của JVM. Vì vậy, khi tạo DateTimeFormatter, hãy thêm một cuộc gọi đến withZone( DateTimeZone.forID( "Europe/Berlin" ) ). (b) Tại sao sử dụng LocalDatetrong daysBetweencuộc gọi? Chỉ cần vượt qua các đối tượng DateTime (FirstTime, secondTime). Đối với ngày đầy đủ, gọi withTimeAtStartOfDays. (c) Tôi sẽ sử dụng tên biến firstDateTimethay vì sau đó firstTimeđể tránh sự mơ hồ giữa các đối tượng ngày, thời gian và ngày giờ. (d) Thêm một số tính năng bắt thử để xử lý dữ liệu đầu vào không phù hợp với định dạng dự kiến ​​của chúng tôi.
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

Khi tôi chạy chương trình của bạn, nó thậm chí không đưa tôi đến điểm mà tôi có thể nhập ngày thứ hai.

Điều này là đơn giản và ít bị lỗi hơn.

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

Chúng tôi có thể sử dụng thư viện java LocalDate và ChronoUnit, Dưới đây mã đang hoạt động tốt. Ngày phải ở định dạng yyyy-MM-dd.

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
Cảm ơn vì muốn đóng góp. Tôi tin rằng đề nghị tốt này đã được trình bày trong câu trả lời của mkobit.
Ole VV
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.