การคำนวณวันระหว่างสองวันด้วย 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?
ริส

1
insert1 = eingabe1 ในภาษาเยอรมัน :)
peter.petrov

@ peter.petrov อ่าเข้าใจแล้ว!
ริส

ฉันคิดว่าเขามีปัญหากับmmและMM: P
Sage

คำตอบ:


230

UPDATE:คำตอบดั้งเดิมจากปี 2556 ล้าสมัยแล้วเนื่องจากบางส่วนของชั้นเรียนได้ถูกแทนที่ วิธีใหม่ในการทำเช่นนี้คือการใช้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();
}

แก้ไข:เนื่องจากมีการสนทนาบางอย่างเกี่ยวกับความถูกต้องของรหัสนี้: มันแน่นอนดูแลปีอธิกสุรทิน อย่างไรก็ตามTimeUnit.DAYS.convertฟังก์ชั่นสูญเสียความแม่นยำเนื่องจากมิลลิวินาทีจะถูกแปลงเป็นวัน (ดูเอกสารที่เชื่อมโยงสำหรับข้อมูลเพิ่มเติม) หากนี่เป็นปัญหาdiffสามารถแปลงด้วยมือได้:

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

หมายเหตุว่านี้เป็นมูลค่าไม่จำเป็นต้องเป็นfloatint


40
นี่เป็นการใช้งานที่ไม่ดีซึ่งไม่นับปีที่ก้าวกระโดดอย่างเหมาะสม
Groovy Ed

3
TimeUnit.DAYS.convert (ต่าง TimeUnit.MILLISECONDS)); <3
Guihgo

3
@GroovyEd จากสิ่งที่ฉันทดสอบดูเหมือนว่ารหัสนี้ไม่มีปัญหากับปีอธิกสุรทิน โปรดทราบว่า TimeUnit.Days.convert () จะเพิกเฉยต่อหน่วยที่เหลือเช่นการแปลง 999 มิลลิวินาทีเป็นวินาทีให้ผลลัพธ์เป็น 0 ซึ่งหมายความว่าหากคุณใช้ Date ใหม่ () เป็นหนึ่งในวัตถุ Date คุณอาจได้รับวันหนึ่งน้อยลง
Klitos G.

3
มันใช้งานได้สำหรับการก้าวกระโดดปีเช่นกัน ตรวจสอบString inputString1 = "28 2 2016"; String inputString2 = "1 3 2016";ans นี้: 2
Rohit Gaikwad

10
ฉันเชื่อว่าสิ่งนี้ทำงานได้อย่างถูกต้องสำหรับปีอธิกสุรทิน แต่มันทำให้เวลาออมแสงลดลง หากสถานที่ของคุณมีเวลาออมแสงทุกปีมีหนึ่งวันที่มี 23 ชั่วโมงและหนึ่งวันที่มี 25 ชั่วโมง วิธีแก้ปัญหานี้สันนิษฐานว่าทุกวันมี 24 ชั่วโมงอย่างไม่ถูกต้อง ดังนั้นจึงให้คำตอบที่ไม่ถูกต้องสำหรับช่วงเวลาใด ๆ ที่เริ่มในระหว่างการประหยัดเวลากลางวันและสิ้นสุดในระหว่างการประหยัดเวลากลางวัน อย่าใช้วิธีแก้ปัญหานี้ - มีวิธีที่ดีกว่า
Dawood ibn Kareem

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
ตรวจสอบอีกครั้ง

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

ใช้ห้องสมุดมาตรฐานได้อย่างยอดเยี่ยม
dieresys

นี่ควรเป็นคำตอบที่ยอมรับในปัจจุบัน การใช้ห้องสมุดมาตรฐานและบัญชีสำหรับปีอธิกสุรทินและการประหยัดเวลากลางวันจะไม่เป็นปัญหา
Pehmolelu

3
นี่คือคำตอบปัจจุบัน / ทันสมัย ​​(คำตอบอื่น ๆ ล้าสมัย) นอกจากนี้ยังบัญชีสำหรับเวลาฤดูร้อน (DST) ที่จะใช้ใน Java 6 หรือ 7 ได้รับThreeTen ย้ายกลับ ในวันที่ไม่ได้ใหม่ของ Android ThreeTenABP
Ole VV

โดยไม่คำนึงถึงการปรับเวลาตามฤดูกาล
Alex

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

จัดการสวิตช์ปรับเวลาตามฤดูกาลได้ดี
Ravi Sanwal

1
+1 สำหรับคำตอบอย่างไรก็ตามต้องการเพิ่มว่าเราต้องการCalendar dayOne = (Calendar) day1.clone(), dayTwo = (Calendar) day2.clone();บรรทัดเนื่องจากให้แน่ใจว่าค่าปฏิทินดั้งเดิมไม่ถูกเขียนทับ ฉันลบเส้นเหล่านี้โดยคิดว่ามันซ้ำซ้อนและเสียเวลาหนึ่งชั่วโมงเพราะความจริงที่ว่าคุณค่าของวัตถุดั้งเดิมของฉันถูกเขียนทับจากภายในฟังก์ชั่นนี้
Rohan Kandwal

2
อย่าลืมว่าค่าเดือนเป็นแบบ 0 ในคลาสปฏิทิน calendar.set (2015, 11, 30, 0, 00, 00); จริง ๆ แล้วหมายถึง 30/12/2015
มิทรี

20

วิธีที่ดีที่สุดและมันจะแปลงเป็นสตริงเป็นโบนัส;)

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

โปรดทราบว่าสิ่งนี้ไม่สามารถใช้งานได้ในปีอธิกสุรทิน ตัวอย่างเช่นจาก "02/15/2020" ถึง "04/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;
}

บัญชีนี้สำหรับปีอธิกสุรทินและการประหยัดเวลากลางวันหรือไม่?
Max Alexander Hanna

1
@ MaxAlexander มันบัญชีสำหรับ leap ปีอย่างถูกต้อง แต่ไม่ใช่ออมแสง มันจะให้คำตอบที่ถูกต้องเมื่อใดก็ตามที่ช่วงเวลาเริ่มต้นในช่วงเวลาที่ไม่ประหยัดเวลากลางวัน แต่สิ้นสุดในช่วงเวลากลางวัน ในกรณีอื่น ๆ ทั้งหมดจะถูกปิดโดยหนึ่ง
Dawood ibn Kareem

1
@saidesh_kilaru "+ 1" คืออะไร ฉันคิดว่าคุณควรลบมัน
อลิสา

ฉันมีปัญหาที่การคัดเลือก INT ทำให้เกิด 4 และการหล่อเพื่อลอยส่งผลให้เป็น 4.9 ดังนั้นนั่นไม่ใช่สิ่งที่ฉันต้องการจริงๆ อาจไม่ชัดเจนพอที่จะอธิบายกรณีสำหรับ date1 เวลา 23:59 น. และ date2 เวลา 00:01 และผลลัพธ์ที่คาดหวังจะเป็นอย่างไร
EricG

10

ไลบรารีวันที่ของ Java เสียหายอย่างฉาวโฉ่ ฉันจะแนะนำให้ใช้Joda เวลา มันจะดูแลปีอธิกสุรทินเขตเวลาและอื่น ๆ สำหรับคุณ

ตัวอย่างการทำงานที่น้อยที่สุด:

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" ) )เพิ่มการเรียกไปยัง (b) ทำไมต้องใช้LocalDateในการdaysBetweenโทร? เพียงผ่านวัตถุ DateTime (firstTime, secondTime) withTimeAtStartOfDaysสำหรับวันเต็มโทร (c) ฉันจะใช้ชื่อตัวแปรfirstDateTimeแทนfirstTimeเพื่อหลีกเลี่ยงความกำกวมระหว่างวัตถุวันที่เวลาและวันที่ (d) เพิ่ม try-catch เพื่อจัดการอินพุตข้อมูลที่ไม่เหมาะสมซึ่งไม่ตรงกับรูปแบบที่คาดหวังของเรา
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

เมื่อฉันรันโปรแกรมของคุณมันไม่ได้ทำให้ฉันถึงจุดที่ฉันสามารถป้อนวันที่ที่สองได้

นี่เป็นข้อผิดพลาดที่ง่ายขึ้นและน้อยลง

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 java library, โค้ดด้านล่างนี้ใช้งานได้ดี วันที่ควรอยู่ในรูปแบบ 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
ขอบคุณที่ต้องการมีส่วนร่วม ฉันเชื่อว่าคำแนะนำที่ดีนี้ได้นำเสนอแล้วในคำตอบโดย mkobit
Ole VV
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.