2010-03-25 188 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); 
    } 
相关问题