2010-03-25 78 views
185

我需要比較兩個Date S(如date1date2),並拿出一個boolean sameDay這是當天兩個Date份額的真實如果不是,則爲false。比較兩個java.util.Dates,看看他們都在同一天

我該怎麼做?這裏似乎有一個混亂的旋風......我想盡量避免在JDK以外的其他依賴項中拉動。

澄清:如果date1date2共享相同的年,月,日,然後sameDay爲真,否則爲假。我意識到這需要知道時區......只要我知道行爲是什麼,那麼通過時區會很好,但我可以與GMT或當地時間一起居住。

再次澄清:

date1 = 2008 Jun 03 12:56:03 
date2 = 2008 Jun 03 12:59:44 
    => sameDate = true 

date1 = 2009 Jun 03 12:56:03 
date2 = 2008 Jun 03 12:59:44 
    => sameDate = false 

date1 = 2008 Aug 03 12:00:00 
date2 = 2008 Jun 03 12:00:00 
    => sameDate = false 
+0

只是爲了澄清 - 你要知道,如果兩個Date對象落在星期的同一天? – 2010-03-25 17:11:59

+0

你想比較完整日期(日,月,年)還是隻有一個月? – XpiritO 2010-03-25 17:13:47

+1

@Rob:不,同一天/每月/每年......我會澄清。 – 2010-03-25 17:13:59

回答

319
Calendar cal1 = Calendar.getInstance(); 
Calendar cal2 = Calendar.getInstance(); 
cal1.setTime(date1); 
cal2.setTime(date2); 
boolean sameDay = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && 
        cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR); 

注意,「同一天」不是那麼簡單的一個概念,因爲它聽起來當不同的時區可以參與。上面的代碼將在這兩個日期計算相對於它運行的計算機使用的時區的日期。如果這不是你所需要的,那麼在你確定你的意思是「同一天」之後,你必須將相關時區傳遞給Calendar.getInstance()電話。

是的,喬達時間的LocalDate將使整個事情更清潔和更容易(雖然涉及時區相同的困難將存在)。

+0

謝謝,看起來它會做我想做的。在我的例子中,我比較了系列中的連續日期,所以看起來我可以在我的系列中使用日曆實例而不是日期實例。 – 2010-03-25 17:20:33

+1

@Jason這可能是也可能不是個好主意。 Calendar的主要問題在於它是一個非常重量級的類,具有很多內部狀態,其中一些用於equals()實現。如果你不平等的日期,不要把它們放到HashMaps中,你應該沒問題。 – 2010-03-25 17:27:47

+0

酷,謝謝,我只是使用比較當前和前一天的邏輯問這裏。應該永遠不會調用「equals」和「hashcode」函數。 – 2010-03-25 18:05:06

128

我使用 「阿帕奇公地郎」 包要做到這一點(即org.apache.commons.lang.time.DateUtils)

boolean samedate = DateUtils.isSameDay(date1, date2); //Takes either Calendar or Date objects 
+0

這使用外部依賴...但很好知道未來。 – 2010-03-25 18:06:28

+13

只需複製源代碼並將其稱爲一天即可:) – 2012-02-29 07:25:52

+7

+1 for using apache.common.lang – Sorter 2013-01-27 05:12:31

281

如何:

SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd"); 
return fmt.format(date1).equals(fmt.format(date2)); 

你也可以如果需要,將時區設置爲SimpleDateFormat。

+2

(我實際上在我的情況下使用SimpleDateFormat,所以它看起來合適。) – 2010-03-25 18:08:57

+4

我真的很驚訝地看到這一點,但即使從性能的角度來看,這個'SimpleDateFormat'方法實際上比另一個使用'Calendar'的方法更快。平均來說,它需要一半的時間作爲「日曆」方法。 (至少在我的系統上)。獎勵! – 2014-07-28 14:16:12

+0

此答案的大部分成本都在SimpleDateFormat創建中。如果你想要更好的性能,把它放在一個singleton的threadLocal字段裏 – Thierry 2015-01-21 09:33:22

17

你能避免外部依賴和使用日曆通過計算Julian Day Number每個日期,然後比較的性能損失,這些:

public static boolean isSameDay(Date date1, Date date2) { 

    // Strip out the time part of each date. 
    long julianDayNumber1 = date1.getTime()/MILLIS_PER_DAY; 
    long julianDayNumber2 = date2.getTime()/MILLIS_PER_DAY; 

    // If they now are equal then it is the same day. 
    return julianDayNumber1 == julianDayNumber2; 
} 
+2

但請注意,這[未考慮到](http://www.xmission.com/~goodhill/dates/deltaDates.html )由於夏令時而改變爲一天的長度。但是直接的'日期'沒有封裝時區的概念,所以沒有辦法非任意地修復這個問題。 – AntoineJ 2011-02-22 14:45:27

+2

這是最快的解決方案 - 非常感謝,正是我一直在尋找的東西;因爲我必須檢查很多日期... – Ridcully 2012-05-11 19:20:45

+1

Nitpick:date1.getTime()不會返回Julian日數,但會自1970-01-01以來的毫秒數。巨大的差異。 – 2017-01-18 09:14:14

-4

您可以將相同的邏輯SimpleDateFormat的解決方案,而不依賴於SimpleDateFormat的

date1.getFullYear()*10000 + date1.getMonth()*100 + date1.getDate() == 
date2.getFullYear()*10000 + date2.getMonth()*100 + date2.getDate() 
+6

這些方法在java.util.Date中不推薦使用。你應該使用日曆來做到這一點。它也是getYear,而不是getFullYear – Kris 2011-11-23 10:34:52

1

除了Binil Thomas液

public static boolean isOnSameDay(Timestamp... dates) { 
    SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd"); 
    String date1 = fmt.format(dates[0]); 
    for (Timestamp date : dates) { 
     if (!fmt.format(date).equals(date1)) { 
      return false; 
     } 
    } 
    return true; 
} 

使用

isOnSameDay(date1,date2,date3 ...); 
//or 
    isOnSameDay(mydates); 
0
public static boolean validSearchRange(String start, String end){ 
    SimpleDateFormat dateFormat = new SimpleDateFormat(clientDateFormat); 
    try { 
     Date start_date = dateFormat.parse(start); 
     Date end_date = dateFormat.parse(end); 
     return !start_date.after(end_date); 
    } catch (ParseException e) { 
     e.printStackTrace(); 
    } 
    return false; 
} 
14

喬達時間

至於添加依賴,恐怕與java.util.Date & .Calendar真的是如此糟糕,我第一件事做任何新項目都要添加Joda-Time庫。在Java 8中,您可以使用受Joda-Time啓發的新的java.time包。

Joda-Time的核心是DateTime類。與java.util.Date不同,它理解其分配的時區(DateTimeZone)。從j.u.Date轉換時,分配一個區域。

DateTimeZone zone = DateTimeZone.forID("America/Montreal"); 
DateTime dateTimeQuébec = new DateTime(date , zone); 

LocalDate

一種驗證如果兩個日期時間降落在同一日期轉換爲LocalDate對象。

該轉換取決於指定的時區。要比較LocalDate對象,它們必須已被轉換爲同一區域。

這是一個小實用方法。

static public Boolean sameDate (DateTime dt1 , DateTime dt2) 
{ 
    LocalDate ld1 = new LocalDate(dt1); 
    // LocalDate determination depends on the time zone. 
    // So be sure the date-time values are adjusted to the same time zone. 
    LocalDate ld2 = new LocalDate(dt2.withZone(dt1.getZone())); 
    Boolean match = ld1.equals(ld2); 
    return match; 
} 

更好的是另一個參數,指定時區而不是假設應該使用第一個DateTime對象的時區。

static public Boolean sameDate (DateTimeZone zone , DateTime dt1 , DateTime dt2) 
{ 
    LocalDate ld1 = new LocalDate(dt1.withZone(zone)); 
    // LocalDate determination depends on the time zone. 
    // So be sure the date-time values are adjusted to the same time zone. 
    LocalDate ld2 = new LocalDate(dt2.withZone(zone)); 
    return ld1.equals(ld2); 
} 

字符串表示

另一種方法是創建每個日期時間的日期部分的字符串表示,然後比較字符串。

同樣,指定的時區至關重要。

DateTimeFormatter formatter = ISODateTimeFormat.date(); // Static method. 
String s1 = formatter.print(dateTime1); 
String s2 = formatter.print(dateTime2.withZone(dt1.getZone()) ); 
Boolean match = s1.equals(s2); 
return match; 

時間

廣義的解決方案是定義一個時間跨度的跨度,然後問,如果跨度包含你的目標。這個示例代碼在Joda-Time 2.4中。請注意,「午夜」相關課程已棄用。而應使用withTimeAtStartOfDay方法。 Joda-Time提供三種類別以各種方式表示一段時間:時間間隔,時間段和持續時間。

使用「半開放」的方法,其中跨度的開始是包容和結束排他。

目標的時區可能與區間的時區不同。

DateTimeZone timeZone = DateTimeZone.forID("Europe/Paris"); 
DateTime target = new DateTime(2012, 3, 4, 5, 6, 7, timeZone); 
DateTime start = DateTime.now(timeZone).withTimeAtStartOfDay(); 
DateTime stop = start.plusDays(1).withTimeAtStartOfDay(); 
Interval interval = new Interval(start, stop); 
boolean containsTarget = interval.contains(target); 

java.time

的Java 8和更高版本自帶的java.time框架。受JSR 310定義的Joda-Time的啓發,並由ThreeTen-Extra項目擴展。見Tutorial

Joda-Time的製造商已經指示我們所有人儘快轉移到java.time。與此同時,喬達時代繼續作爲一個積極維護的項目。但預計未來的工作只能在java.time和ThreeTen-Extra而不是Joda-Time中進行。

簡而言之總結java.time ... Instant是UTC時間軸上的一個時刻。應用時區(ZoneId)獲取ZonedDateTime對象。要離開時間軸,爲了獲得日期時間的模糊不清的想法,請使用「本地」類:LocalDateTimeLocalDate,LocalTime

本答案的Joda-Time部分討論的邏輯適用於java.time。

舊的java.util.Date類有一個新的toInstant轉換爲java.time的方法。

Instant instant = yourJavaUtilDate.toInstant(); // Convert into java.time type. 

確定日期需要時區。

ZoneId zoneId = ZoneId.of("America/Montreal"); 

我們應用該時區對象的Instant獲得ZonedDateTime。由此我們提取僅限日期的值(一個LocalDate),因爲我們的目標是比較日期(而不是小時,分鐘等)。

ZonedDateTime zdt1 = ZonedDateTime.ofInstant(instant , zoneId); 
LocalDate localDate1 = LocalDate.from(zdt1); 

對第二個java.util.Date做同樣的事情我們需要比較。我只是使用當前的時刻。

ZonedDateTime zdt2 = ZonedDateTime.now(zoneId); 
LocalDate localDate2 = LocalDate.from(zdt2); 

使用特殊的isEqual方法來測試相同的日期值。

Boolean sameDate = localDate1.isEqual(localDate2); 
+0

java.time:或者你可以做'LocalDate localDate = LocalDate.fromDateFields(yourJavaUtilDate);' – CyberMew 2017-01-31 04:01:33

+1

@Cyber​​Mew Er?在[我的LocalDate類中]沒有'fromDateFields()'(http://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html)。 – 2017-03-26 09:42:48

+1

對不起,我應該更清楚。該評論與Joda-Time [LocalDate](http://joda-time.sourceforge.net/apidocs/org/joda/time/LocalDate.html)類相關。 – CyberMew 2017-03-26 12:21:18

3

的Java 8

如果你在你的項目中使用Java 8和比較java.sql.Timestamp,你可以使用LocalDate類:

sameDate = date1.toLocalDateTime().toLocalDate().equals(date2.toLocalDateTime().toLocalDate()); 

如果使用java.util.Date,有看看Istvan的答案是不太模糊的。

+0

使用Java 8是一個好主意。你是否假設'date1'和'date2'是'java.sql.Timestamp'?根據問題他們是'Date',我會理解'java.util.Date'。此外,您的代碼使用計算機的時區設置,這在很多情況下都可以使用;我仍然希望在代碼中明確表達這個事實。 – 2017-03-26 09:39:12

+0

@ OleV.V。感謝您的評論,我原來的回答確實是關於'java.sql.Timestamp'。正如你所說,這通常更好地明確設置時區。 – amanteaux 2017-08-14 10:38:22

4

將日期轉換爲Java 8 java.time.LocalDate as seen here

LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); 
LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); 

// compare dates 
assertTrue("Not on the same day", localDate1.equals(localDate2)); 
+0

這是我最喜歡的答案。如果你想控制所用的時區而不是依賴電腦的設置,可以直接輸入,例如'ZoneId.of(「America/Phoenix」)或'ZoneId.of(「Europe/Budapest」)'而不是系統默認。 – 2017-03-26 11:01:54

5
private boolean isSameDay(Date date1, Date date2) { 
     Calendar calendar1 = Calendar.getInstance(); 
     calendar1.setTime(date1); 
     Calendar calendar2 = Calendar.getInstance(); 
     calendar2.setTime(date2); 
     boolean sameYear = calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR); 
     boolean sameMonth = calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH); 
     boolean sameDay = calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH); 
     return (sameDay && sameMonth && sameYear); 
    } 
相關問題