두 개의 java.util.Date를 비교하여 같은 날인지 확인하십시오.


249

나는 두 Dates (예 : date1date2) 를 비교 하고 같은 날에 공유하는 boolean sameDay두 가지 중 사실을 발견해야 Date하며 그렇지 않은 경우에는 false입니다.

어떻게해야합니까? 여기 혼란의 소용돌이가있는 것 같습니다 ... 가능한 경우 JDK 이외의 다른 종속성을 끌어 들이고 싶지 않습니다.

명확히하기 위해 : 경우 date1date2같은 년, 월, 일을 공유하고 sameDaytrue, 그렇지 않으면 false이다. 나는 이것이 시간대에 대한 지식이 필요하다는 것을 알고 있습니다 ... 시간대를 통과하는 것이 좋을 것이지만 행동이 무엇인지 아는 한 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

명확히하기 위해 두 개의 Date 객체가 같은 요일에 해당되는지 알고 싶습니까?
Rob Heiser

전체 날짜 (일, 월, 년) 또는 월의 일만 비교 하시겠습니까?
XpiritO

1
@Rob : 아니요, 같은 요일 / 월 / 년 ... 명확하게 설명하겠습니다.
Jason S

그렇다면 왜 "같음"을 사용하지 않습니까?
XpiritO

7
시간 / 분 / 초가 다르면 같지 않기 때문입니다.
Jason S

답변:


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

"당일"은 다른 시간대가 포함될 수있을 때 들리는 것처럼 단순한 개념이 아닙니다. 위의 코드는 두 날짜 모두에 대해 컴퓨터에서 사용되는 시간대를 기준으로 날짜를 계산합니다. 이것이 필요하지 않은 경우 Calendar.getInstance()"당일"의 의미를 정확히 결정한 후 관련 시간대를 통화로 전달해야합니다.

그리고 예, Joda Time LocalDate은 모든 것을 훨씬 깨끗하고 쉽게 만들 것입니다 (시간대와 관련된 동일한 어려움이있을지라도).


고마워, 내가 원하는 것을 할 것 같습니다. 필자의 경우 연속 날짜를 연속으로 비교하므로 시리즈의 Date 인스턴스 대신 Calendar 인스턴스를 사용할 수있는 것처럼 보입니다.
Jason S

1
@Jason 좋은 생각 일 수도 있고 아닐 수도 있습니다. Calendar의 주요 문제점은 내부 상태가 많은 매우 무거운 클래스이며 일부는 equals () 구현에 사용됩니다. 평등을 위해 날짜를 정리하지 않고 HashMaps에 넣지 않으면 괜찮을 것입니다.
Michael Borgwardt

감사합니다. 여기서 비교 된 현재 및 이전 비교 논리를 사용하고 있습니다. "같음"및 "해시 코드"함수는 절대 호출되지 않아야합니다.
Jason S

1
@UmerHayat : 코드는 월이 아닌 연중 일을 비교합니다. 하나의 적은 비교, 짧은 코드.
Michael Borgwardt

2
제안 : DAY_OF_YEAR을 먼저 비교하면 연도를 확인할 필요가 없습니다. int를 비교하는 것은 정말 비싸지 않지만 ...
Martin P.

332

어때요?

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

필요한 경우 시간대를 SimpleDateFormat으로 설정할 수도 있습니다.


2
(제 어쨌든 SimpleDateFormat을 실제로 사용하고 있기 때문에 적절한 것으로 보입니다.)
Jason S

8
실제로이 사실을보고 놀랐지 만 성능 측면 에서도이 SimpleDateFormat방법은 실제로 Calendars를 사용하여 언급 한 다른 방법보다 빠릅니다 . 평균적으로 Calendar방법 으로 절반의 시간이 걸립니다 . (적어도 내 시스템에서는). 명성!
Michael Plautz

이 답변의 비용은 대부분 SimpleDateFormat 작성에 있습니다. 더 나은 성능을 원한다면 threadLocal 필드를 싱글 톤에 넣으십시오
Thierry

1
나도 스위프트 에서이 작업을 수행합니다. 대부분의 언어에서 그러한 간단한 일이 동일한 핵을 요구하는 것은 놀라운 일입니다. C # 예외-if (d1.Date == d2.Date) ...
alpsystems.com 17시 44 분

2
이것은 추악합니다. 이와 같은 해킹을보고 놀랐습니다.
Zsolt Safrany

162

"apache commons lang"패키지를 사용하여이 작업을 수행합니다 (즉, org.apache.commons.lang.time.DateUtils ).

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

2
이것은 외부 의존성을 사용하지만 미래를 아는 것이 좋습니다.
Jason S

20
그냥 소스를 복사하고 하루에 호출 :)
Anton Kuzmin

그러나 일 중 하나가 null 인 경우 잘못된 인수 예외가 발생하며 경우에 따라 이상적이지 않습니다.
raviraja

1
stackoverflow.com/a/2517824/1665809 에서 언급했듯이 다른 시간대가 관련된 경우이 솔루션이 적합하지 않을 수 있습니다.
mrod

24

각 날짜에 대한 율리우스 일 수 를 계산 한 후 다음을 비교 하여 달력을 사용할 때 외부 종속성 및 성능 저하를 피할 수 있습니다 .

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

4
그러나 일광 절약 시간 제로 인한 기간 변경은 고려하지 않습니다 . 그러나 straight Date는 표준 시간대 개념을 캡슐화하지 않으므로 임의로 수정하는 방법이 없습니다.
AyeJay

3
이것은 가장 빠른 해결책입니다. 정확히 내가 찾던 것입니다. 많은 날짜를 확인해야합니다 ...
Ridcully

2
Nitpick : date1.getTime ()은 Julian Day Number를 반환하지 않지만 1970-01-01 이후 밀리 초를 반환합니다. 큰 차이.
Per Lindberg

2
UTC 시간대에서 비교를 수행합니다. 현지 시간대 또는 지구상의 다른 장소를 원한다면 결과가 정확한지 알 수 없습니다.
Ole VV

20

조다 타임

의존성을 추가하는 것에 관해서는 java.util.Date & .Calendar가 실제로 너무 나빠서 새 프로젝트에 가장 먼저하는 일은 Joda-Time 라이브러리를 추가하는 것입니다. Java 8에서는 Joda-Time에서 영감을 얻은 새로운 java.time 패키지를 사용할 수 있습니다.

Joda-Time의 핵심은 DateTime클래스입니다. java.util.Date와 달리 지정된 시간대 ( DateTimeZone)를 이해합니다 . juDate에서 변환 할 때 영역을 지정하십시오.

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 프레임 워크 가 제공됩니다 . Joda-Time에서 영감을 얻었으며 JSR 310에서 정의했으며 ThreeTen-Extra 프로젝트에서 확장되었습니다. 튜토리얼 참조 .

Joda-Time의 제작자는 우리 모두에게 편리한 시간에 java.time으로 이동하도록 지시했습니다. 그 동안 Joda-Time은 적극적으로 유지 관리되는 프로젝트로 계속 진행됩니다. 그러나 향후 작업은 Joda-Time이 아닌 java.time 및 ThreeTen-Extra에서만 발생할 것으로 예상합니다.

간단히 말해서 java.time을 요약하면… An Instant은 타임 라인의 순간입니다 (UTC). 시간대 ( ZoneId)를 적용하여 ZonedDateTime개체 를 가져옵니다 . 날짜 - 시간의 막연한 부정 아이디어를 얻을, 타임 라인을 이동하려면 "로컬"클래스를 사용 : LocalDateTime, LocalDate,LocalTime .

이 Answer의 Joda-Time 섹션에서 논의 된 논리는 java.time에 적용됩니다.

이전 java.util.Date 클래스에는 toInstantjava.time으로 변환하기위한 새로운 메소드가 있습니다.

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

날짜를 결정하려면 시간대가 필요합니다.

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

해당 시간대 개체를에 적용하여 Instant를 얻습니다 ZonedDateTime. 이를 통해 LocalDate날짜 (시간, 분 등이 아닌)를 비교하는 것이 목적이므로 날짜 전용 값 (a )을 추출합니다 .

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

java.time : 아니면 할 수 있습니다LocalDate localDate = LocalDate.fromDateFields(yourJavaUtilDate);
CyberMew

1
@CyberMew Er? 더 없다 fromDateFields()LocalDate클래스 .
Ole VV

1
죄송합니다. 더 명확해야했습니다. 주석은 Joda-Time LocalDate 클래스 와 관련이 있습니다.
CyberMew

7

여기에 표시된 대로 날짜를 Java 8 java.time.LocalDate 변환 하십시오 .

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

이것은 내가 가장 좋아하는 답변입니다. 오히려 컴퓨터의 설정에 의존하지 않고 사용하는 시간대를 제어하려는 경우, 예를 들어,에 넣어 간단합니다 ZoneId.of("America/Phoenix") 또는 ZoneId.of("Europe/Budapest")대신 시스템 기본으로.
Ole VV

6

자바 8

프로젝트에서 Java 8을 사용하고 비교 java.sql.Timestamp하는 경우 LocalDate클래스를 사용할 수 있습니다 .

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

를 사용하는 경우 java.util.Date덜 모호한 Istvan 답변을 살펴보십시오.


Java 8을 사용하는 것이 좋습니다. 당신은 가정합니다 date1date2있습니다 java.sql.Timestamp? 그들이 질문에 따르면 Date, 나는 이해할 것 java.util.Date입니다. 또한 코드는 컴퓨터의 시간대 설정을 사용하는데,이 설정은 여러 가지 목적으로 적합합니다. 여전히 나는이 사실을 코드에서 명시 적으로 만드는 것을 선호합니다.
Ole VV

@ OleV.V. 귀하의 의견에 감사 드리며, 원래의 대답은 실제로였습니다 java.sql.Timestamp. 당신이 말했듯이 이것은 일반적으로 시간대를 명시 적으로 설정하는 것이 좋습니다.
amanteaux

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

5

안드로이드 사용자 :

당신이 사용할 수있는 DateUtils.isToday(dateMilliseconds)주어진 날짜가 현재 날짜인지 여부를 확인 데 .

API 참조 : https://developer.android.com/reference/android/text/format/DateUtils.html#isToday(long)


1
: API 22부터 사용되지 않습니다이다이 방법을 사용 오브젝트 시간 developer.android.com/reference/android/text/format/Time.html
올렉산드르 Bodashko

2
안드로이드 개발자를위한 +1 이 메소드는 기본 long을 매개 변수로 사용합니다. 간단히 DateUtils.isToday(x.getTime())x 를 사용하면됩니다 (x는 java.util.date 인스턴스 임)
jackycflau

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

1

Kotlin 개발자의 경우 형식화 된 문자열 접근 방식을 비교 한 버전입니다.

val sdf = SimpleDateFormat("yyMMdd")
if (sdf.format(date1) == sdf.format(date2)) {
    // same day
}

가장 좋은 방법은 아니지만 짧고 작동합니다.


1
SimpleDateFormat클래스는 몇 년 전에 java.time.DateTimeFormatterJSR 310에 정의 된 최신 클래스에 의해 대체 되었습니다. 2019 년에 사용을 제안하는 것은 좋지 않은 조언입니다.
Basil Bourque

2
이 코드는 시간대의 중요한 문제를 무시합니다. 주어진 순간, 날짜는 지역마다 다릅니다.
Basil Bourque

-4

SimpleDateFormat에 의존하지 않고 SimpleDateFormat 솔루션과 동일한 논리를 적용 할 수 있습니다.

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

6
이 메소드는 java.util.Date에서 더 이상 사용되지 않습니다. 이를 위해 캘린더를 사용해야합니다. 또한 getFearYear가 아닌 getYear입니다.
Kris
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.