我需要比较两个日期(例如date1和date2),并提出一个布尔的同日,这是真的两个日期共享同一天,如果不是假的。

我该怎么做呢?这里似乎出现了一阵混乱。如果可能的话,我希望避免在JDK之外引入其他依赖项。

澄清:如果date1和date2拥有相同的年、月和日,则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

当前回答

乔达时间

至于添加依赖项,我担心java.util.Date和. calendar真的很糟糕,以至于我对任何新项目所做的第一件事就是添加Joda-Time库。在Java 8中,您可以使用新的Java。时间包,灵感来自Joda-Time。

Joda-Time的核心是DateTime类。不像java.util。日期,它理解它分配的时区(DateTimeZone)。当从j.u.d 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中。注意,与“midnight”相关的类已弃用。相反,使用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。时间框架。灵感来自Joda-Time,由JSR 310定义,并由ThreeTen-Extra项目扩展。看教程。

Joda-Time的创造者已经指示我们所有人转移到java。时间越方便越好。与此同时,Joda-Time继续作为一个积极维护的项目。但预计未来的工作将只在java中进行。time和three - ten - extra而不是Joda-Time。

总结一下java。一个瞬间是UTC时间轴上的一个时刻。应用一个时区(ZoneId)来获得一个zoneeddatetime对象。要脱离时间轴,获得日期-时间的模糊不确定的概念,请使用“本地”类:LocalDateTime、LocalDate、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以获得一个zoneeddatetime。从中提取一个仅限日期的值(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 );

其他回答

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

乔达时间

至于添加依赖项,我担心java.util.Date和. calendar真的很糟糕,以至于我对任何新项目所做的第一件事就是添加Joda-Time库。在Java 8中,您可以使用新的Java。时间包,灵感来自Joda-Time。

Joda-Time的核心是DateTime类。不像java.util。日期,它理解它分配的时区(DateTimeZone)。当从j.u.d 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中。注意,与“midnight”相关的类已弃用。相反,使用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。时间框架。灵感来自Joda-Time,由JSR 310定义,并由ThreeTen-Extra项目扩展。看教程。

Joda-Time的创造者已经指示我们所有人转移到java。时间越方便越好。与此同时,Joda-Time继续作为一个积极维护的项目。但预计未来的工作将只在java中进行。time和three - ten - extra而不是Joda-Time。

总结一下java。一个瞬间是UTC时间轴上的一个时刻。应用一个时区(ZoneId)来获得一个zoneeddatetime对象。要脱离时间轴,获得日期-时间的模糊不确定的概念,请使用“本地”类:LocalDateTime、LocalDate、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以获得一个zoneeddatetime。从中提取一个仅限日期的值(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 );

通过计算每个日期的儒略日数,然后比较这些日期,您可以避免外部依赖关系和使用Calendar的性能影响:

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

在JAVA 8中,我们可以将Date对象转换为LocalDate对象,因此我们可以这样做:

public static boolean isDatesAreDifferentDays(Date date1,Date date2)
{
    LocalDate d1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    LocalDate d2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    if(d1.getDayOfMonth() != d2.getDayOfMonth())
    {
        return false;
    }
    else if(d1.getMonth() != d2.getMonth())
    {
        return false;
    }
    else if(d1.getYear() != d2.getYear())
    {
        return false;
    }
    else
    {
        return true;
    }
}
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);
    }