ההבדל בין שני תאריכים בג'אווה

1. סקירה כללית

במכתב מהיר זה, נבדוק מספר אפשרויות לחישוב ההבדל בין שני תאריכים ב- Java.

2. ליבת ג'אווה

2.1. באמצעות java.util.Date למצוא את ההבדל בימים

נתחיל להשתמש בממשקי ה- API העיקריים של Java כדי לבצע את החישוב ולקבוע את מספר הימים בין שני התאריכים:

@Test הציבור בטל givenTwoDatesBeforeJava8_whenDifferentiating_thenWeGetSix () זורק ParseException {SimpleDateFormat sdf = חדש SimpleDateFormat ("MM / dd / yyyy", אזור.אנגלית); תאריך firstDate = sdf.parse ("24/06/2017"); תאריך secondDate = sdf.parse ("06/30/2017"); diffInMillies ארוך = Math.abs (secondDate.getTime () - firstDate.getTime ()); diff ארוך = TimeUnit.DAYS.convert (diffInMillies, TimeUnit.MILLISECONDS); assertEquals (6, diff); }

2.2. באמצעות java.time.temporal.ChronoUnit למצוא את ההבדל

ממשק ה- Time ב- Java 8 מייצג יחידת זמן תאריך, למשל. שניות או ימים, באמצעות TemporalUnit מִמְשָׁק. כל יחידה מספקת יישום לשיטה בשם בֵּין לחשב את משך הזמן בין שני אובייקטים זמניים במונחים של אותה יחידה ספציפית.

לדוגמא, על מנת לחשב את השניות בין שניים LocalDateTimes:

@Test הציבור בטל givenTwoDateTimesInJava8_whenDifferentiatingInSeconds_thenWeGetTen () {LocalDateTime עכשיו = LocalDateTime.now (); LocalDateTime tenSecondsLater = now.plusSeconds (10); diff ארוך = ChronoUnit.SECONDS.between (עכשיו, tenSecondsLater); assertEquals (10, diff); }

ChronoUnit מספק קבוצה של יחידות זמן קונקרטיות על ידי יישום ה- TemporalUnit מִמְשָׁק. מומלץ מאוד לעשות זאת ייבוא ​​סטטי ה ChronoUnitenum ערכים להשגת קריאות טובה יותר:

ייבא java.time.temporal.ChronoUnit.SECONDS סטטי; // הושמט diff ארוך = SECONDS.between (עכשיו, tenSecondsLater);

כמו כן, אנו יכולים להעביר כל שני אובייקטים זמניים תואמים ל- בֵּין שיטה, אפילו את ZonedDateTime.

מה נהדר ZonedDateTime הוא שהחישוב יעבוד גם אם הם מוגדרים לאזורי זמן שונים:

@Test הציבור בטל givenTwoZonedDateTimesInJava8_whenDifferentiating_thenWeGetSix () {LocalDateTime ldt = LocalDateTime.now (); ZonedDateTime now = ldt.atZone (ZoneId.of ("אמריקה / מונטריאול"); ZonedDateTime sixMinutesBehind = now .withZoneSameInstant (ZoneId.of ("Asia / Singapore")) .minusMinutes (6); diff diff = ChronoUnit.MINUTES.between (sixMinutesBehind, now); assertEquals (6, diff); } 

2.3. באמצעות java.time.temporal.Temporal # עד ()

כל זְמַנִי אובייקט, כגון LocalDate או ZonedDateTime, מספק עד שיטה לחישוב משך הזמן עד לאחר זְמַנִי במונחים של היחידה שצוינה:

@Test הציבור בטל givenTwoDateTimesInJava8_whenDifferentiatingInSecondsUsingUntil_thenWeGetTen () {LocalDateTime עכשיו = LocalDateTime.now (); LocalDateTime tenSecondsLater = now.plusSeconds (10); diff ארוך = now.until (tenSecondsLater, ChronoUnit.SECONDS); assertEquals (10, diff); }

ה זמנית # עד ו TemporalUnit # בין הם שני ממשקי API שונים לאותה פונקציונליות.

2.4. באמצעות java.time. משך זמן ו java.time.Period

ב- Java 8, ה- API של Time הציג שתי מחלקות חדשות: מֶשֶׁך ו פרק זמן.

אם אנו רוצים לחשב את ההבדל בין שני מועדי זמן בפרק זמן מבוסס (שעה, דקות או שניות), נוכל להשתמש מֶשֶׁך מעמד:

@Test הציבור בטל givenTwoDateTimesInJava8_whenDifferentiating_thenWeGetSix () {LocalDateTime עכשיו = LocalDateTime.now (); LocalDateTime sixMinutesBehind = now.minusMinutes (6); משך זמן = משך. בין (עכשיו, sixMinutesBehind); הבדל ארוך = Math.abs (duration.toMinutes ()); assertEquals (6, diff); }

למרות זאת, עלינו להיזהר ממלכודת אם ננסה להשתמש ב- פרק זמן בכיתה לייצג את ההבדל בין שני תאריכים.

דוגמה תסביר את זה במהירות. בואו נחשב כמה ימים בין שני תאריכים באמצעות ה- פרק זמן מעמד:

@Test הציבור בטל givenTwoDatesInJava8_whenUsingPeriodGetDays_thenWorks () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixDaysBehind = aDate.minusDays (6); תקופת תקופה = Period.between (aDate, sixDaysBehind); int diff = Math.abs (period.getDays ()); assertEquals (6, diff); }

אם נבצע את המבחן לעיל, זה יעבור. אנו עשויים לחשוב את פרק זמן הכיתה נוחה לפתור את הבעיה שלנו. בינתיים הכל טוב.

אם דרך זו עובדת בהפרש של שישה ימים, לא נפקפק בכך שהיא תעבוד גם במשך 60 יום.

הבא, בואו לשנות את 6 במבחן לעיל ל 60, ותראה מה קורה:

@Test הציבור בטל givenTwoDatesInJava8_whenUsingPeriodGetDays_thenDoesNotWork () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays (60); תקופת תקופה = Period.between (aDate, sixtyDaysBehind); int diff = Math.abs (period.getDays ()); assertEquals (60, diff); }

כעת, אם נריץ את הבדיקה שוב, נראה:

java.lang.AssertionError: צפוי: 60 בפועל: 29

אופס! מדוע פרק זמן בכיתה מדווחים על ההבדל כ 29 ימים?

הסיבה לכך היא ש פרק זמן מחלקה מייצגת פרק זמן מבוסס תאריך בפורמט "x שנים, y חודשים ו- z ימים“. כשאנחנו קוראים לזה getDays () השיטה, היא מחזירה רק את "ימים zחלק ".

לכן, ה פרק זמן האובייקט במבחן לעיל מחזיק בערך: "0 שנים, חודש ו -29 יום“:

@Test ציבורי בטל givenTwoDatesInJava8_whenUsingPeriod_thenWeGet0Year1Month29Days () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays (60); תקופת תקופה = Period.between (aDate, sixtyDaysBehind); int שנים = Math.abs (period.getYears ()); int חודשים = Math.abs (period.getMonths ()); int ימים = Math.abs (period.getDays ()); assertArrayEquals (int int [] {0, 1, 29}, int int [] {years, months, days}); }

אם ברצוננו לחשב את ההפרש בימים באמצעות API API של זמן של Java 8, ה- ChronoUnit.DAYS.between () השיטה היא הדרך הכי פשוטה.

3. ספריות חיצוניות

3.1. JodaTime

אנחנו יכולים גם לבצע יישום פשוט יחסית עם JodaTime:

 joda-time joda-time 2.9.9 

תוכלו להשיג את הגרסה האחרונה של Joda-time ממייבן סנטרל.

LocalDate מקרה:

@Test הציבור בטל givenTwoDatesInJodaTime_whenDifferentiating_thenWeGetSix () {org.joda.time.LocalDate עכשיו = org.joda.time.LocalDate.now (); org.joda.time.LocalDate sixDaysBehind = now.minusDays (6); diff diff = Math.abs (Days.daysBetween (now, sixDaysBehind) .getDays ()); assertEquals (6, diff); } 

באופן דומה, עם LocalDateTime זה:

@Test הציבור בטל givenTwoDateTimesInJodaTime_whenDifferentiating_thenWeGetSix () {org.joda.time.LocalDateTime עכשיו = org.joda.time.LocalDateTime.now (); org.joda.time.LocalDateTime sixMinutesBehind = now.minusMinutes (6); diff long = Math.abs (Minutes.minutesBetween (now, sixMinutesBehind) .getMinutes ()); assertEquals (6, diff); } 

3.2. Date4J

Date4j מספק יישום פשוט ופשוט, ללא הערה שבמקרה זה עלינו לספק במפורש א אזור זמן.

נתחיל עם התלות של Maven:

 com.darwinsys hirondelle-date4j 1.5.1 

הנה מבחן מהיר שעובד עם התקן תאריך שעה:

@Test ציבורי בטל givenTwoDatesInDate4j_whenDifferentiating_thenWeGetSix () {DateTime now = DateTime.now (TimeZone.getDefault ()); DateTime sixDaysBehind = now.minusDays (6); diff long = Math.abs (now.numDaysFrom (sixDaysBehind)); assertEquals (6, diff); }

4. מסקנה

במדריך זה המחשנו כמה דרכים לחישוב ההבדל בין תאריכים (עם ובלי זמן), הן בג'אווה רגילה והן בשימוש בספריות חיצוניות.

קוד המקור המלא של המאמר זמין באתר GitHub.