두 Java 날짜 인스턴스의 차이 계산


433

java.util.DateScala에서 Java 클래스를 사용 하고 있으며 Date객체와 현재 시간 을 비교하고 싶습니다 . getTime ()을 사용하여 델타를 계산할 수 있다는 것을 알고 있습니다.

(new java.util.Date()).getTime() - oldDate.getTime()

그러나 이것은 단지 long밀리 초를 나타냅니다. 시간 델타를 얻는 더 간단하고 좋은 방법이 있습니까?


10
조다 시간에 대한 사랑이없는 이유는 무엇입니까? Java로 날짜를 처리하려는 경우 거의 가장 좋은 옵션입니다.
닥터 존스

7
Joda를 사용하지 않고 stackoverflow.com/a/10650881/82609
Sebastien Lorber

2
Joda 시간을 추천하고 진정한 Java 답변을 권장하지 않는 모든 사람들에게 부끄러움을
느끼십시오

2
@ Zizouz212 Joda-Time 추천과 관련하여 Java와 함께 번들로 제공되는 이전 날짜-시간 클래스는 나쁘고, 실제로 나쁘고, 잘못 설계되고, 혼란스럽고 번거 롭습니다. Joda-Time이 교체로 큰 성공을 거두었을 정도로 나빴습니다. Sun / Oracle조차도 포기하고 Java 8 이상의 일부로 java.time 패키지를 채택했습니다. java.time 클래스는 Joda-Time에서 영감을 받았습니다. Joda-Time과 java.time은 모두 같은 사람 Stephen Colbourne이 이끌고 있습니다. 나는 말할 것 "사람이 부끄러운의 사용을 추천 Date, CalendarSimpleDateFormat"을.
Basil Bourque

2
Joda Time은 질문을 받았을 때 좋은 대답 이었지만 Java 8을 사용할 수있는 모든 사람에게 가장 적합한 대답은 java.time.Periodand 및 / 또는 Duration입니다. 아래 Basil Bourque의 답변을 참조하십시오 .
Ole VV

답변:


198

JDK DateAPI는 불행히도 크게 망가졌습니다. Joda Time 라이브러리를 사용하는 것이 좋습니다 .

Joda Time에는 시간 간격 개념이 있습니다 .

Interval interval = new Interval(oldTime, new Instant());

편집 : 그런데, Joda는 두 Interval시간 순간 사이의 시간 간격을 나타내는 개념 (8am과 10am 사이 Duration의 시간을 나타냄 )과 실제 시간 경계가없는 시간을 나타내는 것 (예 : 2 시간을 나타냄)이라는 두 가지 개념을 가지고 있습니다.

시간 비교에만 관심이 있다면 대부분의 Date구현 (JDK 포함) Comparable은 사용자가 사용할 수있는 인터페이스를 구현 합니다.Comparable.compareTo()


btw – 당신은 Comparable.compareTo()그렇지 않습니다 Comparable.compare().
Scott Morrison

Joda-Time에는 간격, 기간 및 기간 등 다양한 방법으로 시간 범위를 나타내는 세 가지 클래스가 있습니다. 이 정답은 처음 두 가지에 대해 설명합니다. 기간에 대한 정보는 내 답변 을 참조하십시오 .
Basil Bourque

Java 8에는 joda와 같은 새로운 날짜 및 시간 API가 있습니다.
tbodt

11
java.timeJava 8 의 새로운 패키지는 Joda-Time에서 영감을 얻었지만 드롭 인 대체품은 아닙니다. 각각의 장단점이 있습니다. 다행히도 당신은 그들 사이에서 선택할 필요가 없습니다. import진술에 주의를 기울이는 동안 각각의 장점을 활용하십시오 . java.time의 예를 보려면 이 다른 답변 을 참조하십시오 .
Basil Bourque

6
참고로 Joda-Time 프로젝트는 이제 유지 관리 모드 에 있으며 팀은 java.time 클래스 로의 마이그레이션을 조언합니다 . Oracle의 Tutorial을 참조하십시오 .
Basil Bourque

550

간단한 diff (lib없이)

/**
 * Get a diff between two dates
 * @param date1 the oldest date
 * @param date2 the newest date
 * @param timeUnit the unit in which you want the diff
 * @return the diff value, in the provided unit
 */
public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
    long diffInMillies = date2.getTime() - date1.getTime();
    return timeUnit.convert(diffInMillies,TimeUnit.MILLISECONDS);
}

그리고 당신은 전화 할 수 있습니다 :

getDateDiff(date1,date2,TimeUnit.MINUTES);

두 날짜의 차이를 분 단위로 가져옵니다.

TimeUnitjava.util.concurrent.TimeUnit나노에서 며칠로가는 표준 Java 열거 형입니다.


사람이 읽을 수있는 diff (lib없이)

public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) {

    long diffInMillies = date2.getTime() - date1.getTime();

    //create the list
    List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class));
    Collections.reverse(units);

    //create the result map of TimeUnit and difference
    Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
    long milliesRest = diffInMillies;

    for ( TimeUnit unit : units ) {

        //calculate difference in millisecond 
        long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
        long diffInMilliesForUnit = unit.toMillis(diff);
        milliesRest = milliesRest - diffInMilliesForUnit;

        //put the result in the map
        result.put(unit,diff);
    }

    return result;
}

http://ideone.com/5dXeu6

출력은 Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}단위가 주문 된 것과 같습니다 .

해당 맵을 사용자 친화적 인 문자열로 변환하면됩니다.


경고

위의 코드 스 니펫은 두 순간 사이의 간단한 차이를 계산합니다. 이 게시물 에서 설명한 것처럼 일광 절약 스위치 중에 문제가 발생할 수 있습니다 . 즉, 시간이없는 날짜 사이의 차이를 계산하면 날짜 / 시간이 누락 될 수 있습니다.

내 의견으로는 날짜 차이는 주관적이며 특히 며칠입니다. 당신은 할 수있다:

  • 24 시간 경과 시간 계산 : day + 1-day = 1 day = 24h

  • 일광 절약 시간을 돌보는 경과 시간 수를 세십시오 : day + 1-day = 1 = 24h (그러나 자정 시간과 일광 절약 시간을 사용하면 0 일과 23 시간이 될 수 있습니다)

  • 수 집계 day switches(: P 일광 절약이있는 경우 또는 1H), 경과 시간은 단지 2H 경우에도, 일 오전 11 = 1 일 - + 1 일 오후 1시 수단

일의 날짜 차이 정의가 첫 번째 사례와 일치하면 내 답변이 유효합니다.

JodaTime으로

JodaTime을 사용하는 경우 다음을 사용하여 2 개의 인스턴트 (millies 백업 ReadableInstant) 날짜에 대한 차이를 얻을 수 있습니다.

Interval interval = new Interval(oldInstant, new Instant());

그러나 현지 날짜 / 시간에 대한 차이점을 얻을 수도 있습니다.

// returns 4 because of the leap year of 366 days
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5), PeriodType.years()).getYears() 

// this time it returns 5
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5+1), PeriodType.years()).getYears() 

// And you can also use these static methods
Years.yearsBetween(LocalDate.now(), LocalDate.now().plusDays(365*5)).getYears()

와우, 당신은 정말 오래된 개에게 새로운 트릭을 가르 칠 수 있습니다! 전에는 들어 본 적이 없으며 날짜 차이를 의미있는 문자열로 변환하는 데 매우 유용합니다.
Jeremy Goodell

@SebastienLorber TimeUnit에 차이를 계산하는 방법이 있습니까? "알람은 지금부터 3 일, 4 시간 12 분 동안 설정됩니다".
likejudo

화려한 물건은 정말 많은 시간을 절약했습니다. 당신의 도움을 주셔서 감사합니다.
Lyju I Edwinson

Java Dates를 처리하는 데 3 일을 낭비했으며 방금 많은 것을 버리고 이것을 대체했습니다. 감사합니다.
user1091524

이것은 내가 stackoverflow에 온 이후 본 최고의 답변입니다! : D : D : D
Cold

153
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime()) 
                 / (1000 * 60 * 60 * 24) )

이것은 UTC 날짜와 함께 작동하므로 현지 날짜를 보면 차이가 날 수 있습니다. 현지 날짜와 올바르게 작동하려면 일광 절약 시간으로 인해 완전히 다른 방법이 필요합니다.


6
이것은 실제로 Android에서 올바르게 작동하지 않습니다. 반올림 오류가 존재합니다. 5 월 19 일부터 21 일까지는 1.99에서 1까지의 캐스팅을하기 때문에 1 일이라고합니다. int로 캐스팅하기 전에 round를 사용하십시오.
Pratik Mandrekar

4
이것이 가장 좋고 가장 간단한 답변입니다. 두 날짜의 차이를 계산할 때 현지 시간대가 서로 빼기 ... (86400.0 * 1000.0); ... 두 배로, 소수 요일도 있으며 HH : MM : ss로 쉽게 변환 할 수 있습니다.
scottb

8
@ scottb : 현지 날짜의 문제는 일광 절약 시간을 가질 수 있다는 것입니다. 즉, 하루에 23 또는 25 시간이 걸리므로 결과가 엉망이 될 수 있습니다.
Michael Borgwardt

1
@Steve :이 새로운 Date (115, 2, 26)와 같이 정의 할 때 28입니다. (매개 변수에 대한 API 문서에주의하십시오). 2015 년 3 월 26 일이 2015 년 26 개월의 3 번째 날로 해석되도록 미국 날짜 형식을 사용하고 무성한 모드로 구문 분석 할 수 있습니까?
Michael Borgwardt

1
@Steve : 흠, 왜 전에 다른 결과를 얻었는지 확실하지 않지만 이제는 오류를 재현 할 수 있습니다. 코드의 중괄호가 내 대답과 다르 므로 최종 결과 대신 (endDate.getTime() - startDate.getTime())캐스트되고 int정수 오버플로가 발생합니다.
Michael Borgwardt

54

Java 8 이상에 내장 된 java.time 프레임 워크 사용 :

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
Duration duration = Duration.between(oldDate, now);
System.out.println("ISO-8601: " + duration);
System.out.println("Minutes: " + duration.toMinutes());

산출:

ISO-8601 : PT24H10M

분 : 1450

자세한 내용은 Oracle TutorialISO 8601 표준을 참조하십시오 .


5
이것은 날짜 Period대신에 사용하십시오 Duration.
Aphex

53

문제를보다 명확하게 정의해야합니다. 당신은 할 수 단지 둘 사이의 밀리 초 단위로 가지고 Date예를 들어, 24 시간을 밀리 초 단위로 개체와 나누기 :하지만 ...

  • 시간대를 고려하지 않습니다- Date항상 UTC
  • 일광 절약 시간을 고려하지 않습니다 (예를 들어 23 시간 밖에 걸리지 않는 날이있을 수 있음)
  • UTC 내에서도 8 월 16 일 오후 11 시부 터 8 월 18 일 오전 2 시까 지 며칠이 있습니까? 27 시간 밖에 안 남았나요? 아니면 3 개의 날짜를 다루므로 3 일이되어야합니까?

1
나는 java.util을 생각했다. 날짜는 로컬 (기본) 시간대로 해석되어 시간 단위로 표시되는 작은 래퍼입니다. 날짜를 인쇄하면 현지 시간대로 표시됩니다. 내가 여기 혼란스러워?
Adriaan Koster

46

tl; dr

사용하지 않는 java.util.Date개체를 대체물로 변환하십시오 java.time.Instant. 그런 다음 경과 시간을로 계산하십시오 Duration.

Duration d = 
    Duration.between(                   // Calculate the span of time between two moments as a number of hours, minutes, and seconds.
        myJavaUtilDate.toInstant() ,    // Convert legacy class to modern class by calling new method added to the old class.
        Instant.now()                   // Capture the current moment in UTC. About two and a half hours later in this example.
    )
;

d.toString () : PT2H34M56S

d.toMinutes () : 154

d.toMinutesPart () : 34

ISO 8601 형식 : PnYnMnDTnHnMnS

합리적인 표준 ISO 8601 은 시간 범위의 간결한 텍스트 표현을 몇 년, 월, 일, 시간 등으로 정의합니다. 표준은 그러한 기간을 기간 이라고 부릅니다 . 형식은 PnYnMnDTnHnMnS를 Where P수단 "기간"은이 T시간 부분의 일 부분을 분리하고, 다음에 문자 숫자 사이.

예 :

  • P3Y6M4DT12H30M5S
    3 년, 6 개월, 4 일, 12 시간, 30 분 및 5 초
  • PT4H30M
    4 시간 반

java.time

Java 8 이상에 내장 된 java.time 프레임 워크는 번거로운 이전 java.util.Date/ java.util.Calendar클래스를 대체합니다 . 새로운 클래스는 개념적으로 유사하지만 재구성 된 후계자로 의도 된 매우 성공적인 Joda-Time 프레임 워크에서 영감을 얻었습니다 . JSR 310에 의해 정의됩니다 . ThreeTen-Extra 프로젝트로 확장되었습니다 . 학습서를 참조하십시오 .

순간

Instant클래스는 나노초 의 해상도 (소수점의 최대 9 자리)로 UTC 의 타임 라인에서 순간을 나타냅니다 .

Instant instant = Instant.now() ;  // Capture current moment in UTC.

Date/ 와 같은 레거시 클래스를 피하는 것이 가장 Calendar좋습니다. 그러나 아직 java.time으로 업데이트되지 않은 이전 코드와 상호 운용해야하는 경우 앞뒤로 변환하십시오. 이전 클래스에 추가 된 새 변환 메소드를 호출하십시오. 에서로 이동 java.util.Date하려면을 (를 Instant) 호출하십시오 Date::toInstant.

Instant instant = myJavaUtilDate.toInstant() ;  // Convert from legacy `java.util.Date` class to modern `java.time.Instant` class.

시간의 경간

java.time 클래스는 시간 범위를 몇 년, 월, 일, 시간, 분, 초로 나타내는이 아이디어를 두 개의 반으로 나눕니다.

  • Period 몇 년, 몇 달, 며칠 동안
  • Duration 일, 시간, 분, 초 동안

다음은 예입니다.

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime future = now.plusMinutes ( 63 );
Duration duration = Duration.between ( now , future );

콘솔로 덤프하십시오.

모두 PeriodDuration사용 ISO 8601 의 가치의 String 표현을 생성하기위한 표준.

System.out.println ( "now: " + now + " to future: " + now + " = " + duration );

지금 : 2015-11-26T00 : 46 : 48.016-05 : 00 [미국 / 몬트리올]에서 미래로 : 2015-11-26T00 : 46 : 48.016-05 : 00 [미국 / 몬트리올] = PT1H3M

Java 9는 Duration일 부분, 시간 부분, 분 부분 및 초 부분을 가져 오는 메소드를 추가합니다 .

전체 지속 시간에서 총 일 수, 시간 또는 분 또는 초 또는 밀리 초 또는 나노초를 얻을 수 있습니다.

long totalHours = duration.toHours();

Java 9에서 Duration클래스는 일,시, 분, 초, 밀리 초 / 나노초의 다양한 부분을 반환 하기 위한 새로운 메소드얻습니다 . , 등 의 to…Part메소드를 호출하십시오 .toDaysPart()toHoursPart()

ChronoUnit

"일수"와 같이 더 간단한 시간 단위 만 신경 쓰는 경우 ChronoUnit열거 형을 사용하십시오 .

long daysElapsed = ChronoUnit.DAYS.between( earlier , later );

또 다른 예.

Instant now = Instant.now();
Instant later = now.plus( Duration.ofHours( 2 ) );

long minutesElapsed = ChronoUnit.MINUTES.between( now , later );

120


java.time에 대하여

java.time의 프레임 워크는 나중에 자바 8에 내장되어 있습니다. 이 클래스는 까다로운 기존에 대신 기존 과 같은 날짜 - 시간의 수업을 java.util.Date, Calendar, SimpleDateFormat.

Joda 타임 프로젝트는 현재의 유지 관리 모드 , java.time로 마이그레이션을 조언한다.

자세한 내용은 Oracle Tutorial을 참조하십시오 . 많은 예제와 설명을 보려면 스택 오버플로를 검색하십시오. 사양은 JSR 310 입니다.

java.time 클래스는 어디서 구할 수 있습니까?

ThreeTen - 추가 프로젝트 추가 클래스와 java.time를 확장합니다. 이 프로젝트는 향후 java.time에 추가 될 수있는 입증 된 근거입니다. 당신은 여기에 몇 가지 유용한 클래스와 같은 찾을 수 있습니다 Interval, YearWeek, YearQuarter, 그리고 .


조다 타임

업데이트 : Joda-Time 프로젝트는 이제 유지 관리 모드 에 있으며 팀은 java.time 으로의 마이그레이션을 조언합니다. 클래스 . 나는 역사를 위해이 섹션을 그대로 둡니다.

Joda-Time 라이브러리는 기본값으로 ISO 8601을 사용합니다. 이 Period클래스는 이러한 PnYnMnDTnHnMnS 문자열을 구문 분석하고 생성합니다.

DateTime now = DateTime.now(); // Caveat: Ignoring the important issue of time zones.
Period period = new Period( now, now.plusHours( 4 ).plusMinutes( 30));
System.out.println( "period: " + period );

렌더 :

period: PT4H30M

"tl; dr"로 텍스트와 관련이없는 질문을 시작한 것은 재밌습니다. 문제는 X 전 또는 X 단위에서 타임 스탬프를 얻는 방법이 아니라 두 날짜 사이의 델타를 얻는 방법에 관한 것입니다. 그게 다야.
버팔로

@ 버팔로 귀하의 의견을 이해하지 못합니다. 내 대답은 포함한다 Period, Duration그리고 ChronoUnit그 목적은 세 가지 클래스 시간의 점 사이의 델타를 결정하는 것입니다. 내 "텍스트 벽"의 어느 부분이 관련이 없는지 알려주십시오. 그리고 당신은 질문에“날짜 사이의 델타”를 요구했다는 잘못된 점이 있습니다. 질문 Date은 그 클래스의 불행한 명명에도 불구하고“날짜”가 아닌 날짜-시간 순간 인 객체 사이의 델타를 요구했습니다 .
Basil Bourque

귀하의 의견에는 두 개의 기존 java.util.Date 객체를 처리하는 것이 없습니다. 내 코드에서 다양한 스 니펫을 사용해 보았지만 java.util.Date 객체를 사용하는 것은 없습니다.
버팔로

@ 버팔로 페어, 좋은 비판. "tl; dr"섹션에 a java.util.Date에서 Instant(just call .toInstant) 로 변환하는 코드를 추가했습니다 . 그리고 Moment설명 할 섹션을 추가했습니다 . 한 쌍의 Date객체를 언급 했지만 실제로 질문은 기존의 단일 Date객체 만 사용 하고 현재 순간을 캡처하므로 동일한 작업을 수행했습니다. 피드백을 주셔서 감사합니다! 팁 : 사용을 포기하십시오 Date– 레거시 클래스는 정말 끔찍한 혼란입니다.
Basil Bourque


23

약간 더 간단한 대안 :

System.currentTimeMillis() - oldDate.getTime()

"nicer"는 정확히 무엇을 필요로합니까? 기간을 여러 시간 및 일 등으로 나타내는 데 따른 문제점은 날짜의 복잡성으로 인해 부정확하고 잘못된 기대로 이어질 수 있다는 것입니다 (예 : 일광 절약 시간으로 인해 23 일 또는 25 시간이 소요될 수 있음).


22

밀리 초 방식을 사용하면 일부 로케일에서 문제가 발생할 수 있습니다.

예를 들어, 2007 년 3 월 24 일과 2007 년 3 월 25 일의 두 날짜의 차이는 1 일이어야합니다.

그러나 영국에서 밀리 초 경로를 사용하면 0 일이 소요됩니다.

/** Manual Method - YIELDS INCORRECT RESULTS - DO NOT USE**/  
/* This method is used to find the no of days between the given dates */  
public long calculateDays(Date dateEarly, Date dateLater) {  
   return (dateLater.getTime() - dateEarly.getTime()) / (24 * 60 * 60 * 1000);  
} 

이것을 구현하는 더 좋은 방법은 java.util.Calendar를 사용하는 것입니다

/** Using Calendar - THE CORRECT WAY**/  
public static long daysBetween(Calendar startDate, Calendar endDate) {  
  Calendar date = (Calendar) startDate.clone();  
  long daysBetween = 0;  
  while (date.before(endDate)) {  
    date.add(Calendar.DAY_OF_MONTH, 1);  
    daysBetween++;  
  }  
  return daysBetween;  
}  

19
이 코드의 원래 작성자와 블로그 항목이 2007 년으로 거슬러 올라간 세 번째 문장에 크레딧을 주실 수 있습니까?
wchargin

조금 비 효과적이지 않습니까?
Gangnus

제대로 작동하지 않습니다. daysBetween (new GregorianCalendar (2014,03,01), new GregorianCalendar (2014,04,02))); 31을 반환하고 32를 반환해야합니다. timeanddate.com/date/…
marcolopes

5
@marcolopes-달력 월은 0을 기준으로하기 때문에 틀 렸습니다. 나는 당신이 3 월 / 4 월을 의미한다고 확신하지만, 당신이 테스트하는 것은 4 월 / 6 월은 31입니다.-> 새 GregorianCalendar (2014, Calendar.MARCH, 1)처럼 안전하게 작성하십시오 ....
삼촌 Iroh

@ UncleIroh, 당신이 맞아요! 중요한 사실을 놓쳤습니다 (달력은 0을 기준으로 함). 이 질문을 다시 한 번 검토해야합니다.
marcolopes 2016 년

22

날짜와 시간의 차이를 찾을 수있는 방법은 여러 가지가 있습니다. 내가 아는 가장 간단한 방법 중 하나는 다음과 같습니다.

      Calendar calendar1 = Calendar.getInstance();
      Calendar calendar2 = Calendar.getInstance();
      calendar1.set(2012, 04, 02);
      calendar2.set(2012, 04, 04);
      long milsecs1= calendar1.getTimeInMillis();
      long milsecs2 = calendar2.getTimeInMillis();
      long diff = milsecs2 - milsecs1;
      long dsecs = diff / 1000;
      long dminutes = diff / (60 * 1000);
      long dhours = diff / (60 * 60 * 1000);
      long ddays = diff / (24 * 60 * 60 * 1000);

      System.out.println("Your Day Difference="+ddays);

print 문은 단지 예일뿐입니다. 원하는 방식으로 형식을 지정할 수 있습니다.


5
@ manoj kumar bardhan : 스택 오버플로에 오신 것을 환영합니다. 질문과 대답은 오래되었습니다. 답변이 기존 질문보다 답변 / 질문에 더 많이 추가되어야합니다.
Jayan

3
DST 전환으로 인해 23 시간 또는 25 시간이 걸리는 날은 어떻습니까?
Joni

19

여기에있는 모든 대답은 정확하지만 joda 또는 이와 유사한 레거시 Java 또는 타사 라이브러리를 사용 하므로 Java 8 이상에서 새로운 java.time 클래스를 사용하여 다른 방법을 사용하지 않을 것 입니다. 오라클 튜토리얼 참조 .

사용 LocalDateChronoUnit:

LocalDate d1 = LocalDate.of(2017, 5, 1);
LocalDate d2 = LocalDate.of(2017, 5, 18);

long days = ChronoUnit.DAYS.between(d1, d2);
System.out.println( days );

9

(다른 게시물에 설명 된대로),하지만 당신은 밀리 초 작품의 날짜를 빼면 날짜의 시간 부분을 삭제하는 경우 HOUR_OF_DAY하지 HOUR을 사용 :

public static final long MSPERDAY = 60 * 60 * 24 * 1000;
...
final Calendar dateStartCal = Calendar.getInstance();
dateStartCal.setTime(dateStart);
dateStartCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateStartCal.set(Calendar.MINUTE, 0);
dateStartCal.set(Calendar.SECOND, 0);
dateStartCal.set(Calendar.MILLISECOND, 0);
final Calendar dateEndCal = Calendar.getInstance();
dateEndCal.setTime(dateEnd);
dateEndCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateEndCal.set(Calendar.MINUTE, 0);
dateEndCal.set(Calendar.SECOND, 0);
dateEndCal.set(Calendar.MILLISECOND, 0);
final long dateDifferenceInDays = ( dateStartCal.getTimeInMillis()
                                  - dateEndCal.getTimeInMillis()
                                  ) / MSPERDAY;
if (dateDifferenceInDays > 15) {
    // Do something if difference > 15 days
}

1
표준 라이브러리를 벗어나지 않고 두 달력 날짜의 차이를 결정하는 가장 좋은 방법입니다. 다른 답변의 대부분은 하루를 임의의 24 시간으로 처리합니다. 윤초를 더하기보다는 빼기 만한다면, 절대 차이가 MSPERDAY의 배수의 배수보다 약간 작을 수 있기 때문에 잘림으로 인해 최종 계산이 1만큼 줄어들 수 있습니다.
JulianSymes

8

JodaTime 또는 이와 유사한 것을 사용하지 않으려면 가장 좋은 해결책은 다음과 같습니다.

final static long MILLIS_PER_DAY = 24 * 3600 * 1000;
long msDiff= date1.getTime() - date2.getTime();
long daysDiff = Math.round(msDiff / ((double)MILLIS_PER_DAY));

일별 ms 수는 일광 절약 시간과 윤초로 인해 항상 동일하지는 않지만 매우 가까우며 일광 절약 시간으로 인한 편차는 더 오랜 기간 동안 취소됩니다. 따라서 나누고 반올림하면 올바른 결과를 얻을 수 있습니다 (적어도 사용 된 로컬 달력에 DST 및 윤초 이외의 이상한 시간 점프가 포함되어 있지 않는 한).

이 여전히를 가정합니다 date1date2하루 중 같은 시간으로 설정됩니다. Jon Skeet이 지적한대로 하루 중 다른 시간에 대해 먼저 "날짜 차이"의 의미를 정의해야합니다.


문제는 date1.getTime()vs에 date2.getTime()있습니다. 따라서 2016-03-03에서 2016-03-31을 비교하면 28 일을 계산하는 동안 27 일을 계산합니다.
malat

@malat : 죄송합니다. 따라갈 수 없습니다. 방금 시도했습니다. 코드를 28 일로 계산하여 2016-03-03에서 2016-03-31을 비교합니다. 예제에서 다른 것을 계산하는 경우 별도의 질문으로 고려하십시오.
sleske

또한 내 경고를 읽었습니까? "여전히 date1과 date2가 같은 시간으로 설정되어 있다고 가정합니다." 시험에서 다른 시간대를 사용 했습니까?
sleske

아 맞아! 와 같은 트릭을 놓쳤습니다. Math.round()'실제 세계'캘린더에서는 안전합니다. 소음이 유감입니다.
malat

8

개선 된 Java 용 Date / Time API 인 Joda Time을 살펴보고 Scala와 잘 작동합니다.


Java 8에서 java.time (JSR-310)으로 대체 됨
malat

5

Joda Interval과 Days의 차이점을 보여 드리겠습니다.

DateTime start = new DateTime(2012, 2, 6, 10, 44, 51, 0);
DateTime end = new DateTime(2012, 2, 6, 11, 39, 47, 1);
Interval interval = new Interval(start, end);
Period period = interval.toPeriod();
System.out.println(period.getYears() + " years, " + period.getMonths() + " months, " + period.getWeeks() + " weeks, " + period.getDays() + " days");
System.out.println(period.getHours() + " hours, " + period.getMinutes() + " minutes, " + period.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *1 weeks, 1 days*
//0 hours, 54 minutes, 56 seconds 

//Period can set PeriodType,such as PeriodType.yearMonthDay(),PeriodType.yearDayTime()...
Period p = new Period(start, end, PeriodType.yearMonthDayTime());
System.out.println(p.getYears() + " years, " + p.getMonths() + " months, " + p.getWeeks() + " weeks, " + p.getDays() + "days");
System.out.println(p.getHours() + " hours, " + p.getMinutes() + " minutes, " + p.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *0 weeks, 8 days*
//0 hours, 54 minutes, 56 seconds 

5

"2 Days 03h 42m 07s"와 같은 형식의 리턴 문자열이 필요한 경우 다음을 시도하십시오.

public String fill2(int value)
{
    String ret = String.valueOf(value);

    if (ret.length() < 2)
        ret = "0" + ret;            
    return ret;
}

public String get_duration(Date date1, Date date2)
{                   
    TimeUnit timeUnit = TimeUnit.SECONDS;

    long diffInMilli = date2.getTime() - date1.getTime();
    long s = timeUnit.convert(diffInMilli, TimeUnit.MILLISECONDS);

    long days = s / (24 * 60 * 60);
    long rest = s - (days * 24 * 60 * 60);
    long hrs = rest / (60 * 60);
    long rest1 = rest - (hrs * 60 * 60);
    long min = rest1 / 60;      
    long sec = s % 60;

    String dates = "";
    if (days > 0) dates = days + " Days ";

    dates += fill2((int) hrs) + "h ";
    dates += fill2((int) min) + "m ";
    dates += fill2((int) sec) + "s ";

    return dates;
}

2
Joda-Time이 이미 작성 및 디버깅 된 Period 클래스를 제공 할 때 왜 자신의 역할을 수행 합니까?
Basil Bourque

8
32 줄의 코드 만 필요할 때 압축 파일 크기가 4.1MB 인 라이브러리를 다운로드하여 프로젝트에 추가해야하는 이유는 무엇입니까 ???
Ingo

1
Joda-Time은 감자 칩과 같기 때문에 하나만 먹을 수는 없습니다. 모든 곳에서 Joda-Time을 사용하게됩니다. 그리고 Joda-Time은 잘 테스트되고 잘 작성된 코드이기 때문입니다. Joda-Time은 표준 ISO 8601 Duration 문자열을 구문 분석하고 생성하므로 이러한 값을 직렬화하거나보고하는 데 편리 할 수 ​​있습니다. Joda-Time에는 이러한 값의 현지화 된 표현을 인쇄하는 포맷터가 포함되어 있기 때문입니다.
Basil Bourque

모든 코드가 테스트되는 것은 아닙니다. std위는 정의되어 있지 않습니다.
Basil Bourque

@Basil Bourque : 힌트를위한 Thx. 나는 출처를 알아 냈습니다. 이 오류는 번역에서 영어로 발생했습니다.
Ingo

5

참고 : startDate 및 endDates는-> java.util.Date입니다.

import org.joda.time.Duration;
import org.joda.time.Interval;
// Use .getTime() unless it is a joda DateTime object
Interval interval = new Interval(startDate.getTime(), endDate.getTime());
Duration period = interval.toDuration();
//gives the number of days elapsed between start 
period.getStandardDays();

종료일

일과 마찬가지로 시간, 분 및 초도 얻을 수 있습니다

period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();

4

여기 예를 확인하십시오 http://www.roseindia.net/java/beginners/DateDifferent.shtml 이 예는 일,시, 분, 초 및 밀리 초의 차이를 보여줍니다. :).

import java.util.Calendar;
import java.util.Date;

public class DateDifferent {
    public static void main(String[] args) {
        Date date1 = new Date(2009, 01, 10);
        Date date2 = new Date(2009, 07, 01);
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();
        calendar1.setTime(date1);
        calendar2.setTime(date2);
        long milliseconds1 = calendar1.getTimeInMillis();
        long milliseconds2 = calendar2.getTimeInMillis();
        long diff = milliseconds2 - milliseconds1;
        long diffSeconds = diff / 1000;
        long diffMinutes = diff / (60 * 1000);
        long diffHours = diff / (60 * 60 * 1000);
        long diffDays = diff / (24 * 60 * 60 * 1000);
        System.out.println("\nThe Date Different Example");
        System.out.println("Time in milliseconds: " + diff + " milliseconds.");
        System.out.println("Time in seconds: " + diffSeconds + " seconds.");
        System.out.println("Time in minutes: " + diffMinutes + " minutes.");
        System.out.println("Time in hours: " + diffHours + " hours.");
        System.out.println("Time in days: " + diffDays + " days.");
    }
}

3
-1 Date 인스턴스가 UTC 시간에서 파생되지 않으면 잘못되었습니다. Jon Skeet의 답변을 참조하십시오.
sleske

4

GMT 시간대를 사용하여 캘린더의 인스턴스를 가져오고 Calendar 클래스의 set 메소드를 사용하여 시간을 설정하십시오. GMT 시간대에는 0 오프셋 (실제 중요하지 않음)이 있으며 일광 절약 시간 플래그가 false로 설정되어 있습니다.

    final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 9);
    cal.set(Calendar.DAY_OF_MONTH, 29);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date startDate = cal.getTime();

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 12);
    cal.set(Calendar.DAY_OF_MONTH, 21);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date endDate = cal.getTime();

    System.out.println((endDate.getTime() - startDate.getTime()) % (1000l * 60l * 60l * 24l));

밀리 초 부분을 0으로 설정하는 것을 잊지 마십시오 java.util.Date. 구 클래스 등의 맥락에서 좋은 해답입니다 . 해킹을 사용하여 시간대를 GMT로 설정하면 코드가 일광 절약 효과에 영향을받지 않습니다.
Meno Hochschild

4

다음 코드는 원하는 출력을 제공 할 수 있습니다.

String startDate = "Jan 01 2015";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
LocalDate date = LocalDate.parse(startDate, formatter);

String currentDate = "Feb 11 2015";
LocalDate date1 = LocalDate.parse(currentDate, formatter);

System.out.println(date1.toEpochDay() - date.toEpochDay());

3
코드의 기능을 정확하게 설명 할 수 있습니까? 질문은 타임 델타에 대해 묻는 것처럼 보이며 언뜻보기에 코드가 하루 델타를 반환하는 것처럼 보입니까?
GHC

4
public static String getDifferenceBtwTime(Date dateTime) {

    long timeDifferenceMilliseconds = new Date().getTime() - dateTime.getTime();
    long diffSeconds = timeDifferenceMilliseconds / 1000;
    long diffMinutes = timeDifferenceMilliseconds / (60 * 1000);
    long diffHours = timeDifferenceMilliseconds / (60 * 60 * 1000);
    long diffDays = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24);
    long diffWeeks = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 7);
    long diffMonths = (long) (timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 30.41666666));
    long diffYears = (long)(timeDifferenceMilliseconds / (1000 * 60 * 60 * 24 * 365));

    if (diffSeconds < 1) {
        return "one sec ago";
    } else if (diffMinutes < 1) {
        return diffSeconds + " seconds ago";
    } else if (diffHours < 1) {
        return diffMinutes + " minutes ago";
    } else if (diffDays < 1) {
        return diffHours + " hours ago";
    } else if (diffWeeks < 1) {
        return diffDays + " days ago";
    } else if (diffMonths < 1) {
        return diffWeeks + " weeks ago";
    } else if (diffYears < 12) {
        return diffMonths + " months ago";
    } else {
        return diffYears + " years ago";
    }
}   

3
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;

5
-1 Date 인스턴스가 UTC 시간에서 파생되지 않으면 잘못되었습니다. Jon Skeet의 답변을 참조하십시오.
sleske

5
@sleske 당신이 옳지 않다. 그는를 사용하여 시간대 정보를 이미 잃어 버렸 Date으므로 이러한 비교는 상황에 따라 달성 할 수있는 최고입니다.
Bozho

1
좋아, 우리 둘 다 맞아 Date 인스턴스의 출처에 따라 다릅니다. 여전히 언급해야 할 것은 흔한 실수입니다.
sleske

솔루션을 사용할 때 유형 불일치 : long에서 int로 변환 할 수 없습니다. 캐스팅도 추가해야합니까, 아니면 뭔가 빠졌습니까?
Ad Infinitum

3

가장 좋은 것은

(Date1-Date2)/86 400 000 

이 숫자는 하루 의 밀리 초 수 입니다.

하나의 날짜와 다른 날짜는 밀리 초 단위의 차이를 제공합니다.

이중 변수로 답을 수집하십시오 .


그래 왜 안돼? 몇 가지 방법으로 질문의 요점을 이해하지 못합니다 .OP에는 ms의 차이가 있습니다 ... 하루에 특정 수의 ms가 있습니다 (푸른 달에 한 번 천문학적으로 조정하면 OK이지만 OP는 그것이 천문학 자들이 필요로하는만큼 정확해야한다고 말하지
mike rodent

3

다음은 종속성이없는 O (1)의 올바른 Java 7 솔루션입니다.

public static int countDaysBetween(Date date1, Date date2) {

    Calendar c1 = removeTime(from(date1));
    Calendar c2 = removeTime(from(date2));

    if (c1.get(YEAR) == c2.get(YEAR)) {

        return Math.abs(c1.get(DAY_OF_YEAR) - c2.get(DAY_OF_YEAR)) + 1;
    }
    // ensure c1 <= c2
    if (c1.get(YEAR) > c2.get(YEAR)) {
        Calendar c = c1;
        c1 = c2;
        c2 = c;
    }
    int y1 = c1.get(YEAR);
    int y2 = c2.get(YEAR);
    int d1 = c1.get(DAY_OF_YEAR);
    int d2 = c2.get(DAY_OF_YEAR);

    return d2 + ((y2 - y1) * 365) - d1 + countLeapYearsBetween(y1, y2) + 1;
}

private static int countLeapYearsBetween(int y1, int y2) {

    if (y1 < 1 || y2 < 1) {
        throw new IllegalArgumentException("Year must be > 0.");
    }
    // ensure y1 <= y2
    if (y1 > y2) {
        int i = y1;
        y1 = y2;
        y2 = i;
    }

    int diff = 0;

    int firstDivisibleBy4 = y1;
    if (firstDivisibleBy4 % 4 != 0) {
        firstDivisibleBy4 += 4 - (y1 % 4);
    }
    diff = y2 - firstDivisibleBy4 - 1;
    int divisibleBy4 = diff < 0 ? 0 : diff / 4 + 1;

    int firstDivisibleBy100 = y1;
    if (firstDivisibleBy100 % 100 != 0) {
        firstDivisibleBy100 += 100 - (firstDivisibleBy100 % 100);
    }
    diff = y2 - firstDivisibleBy100 - 1;
    int divisibleBy100 = diff < 0 ? 0 : diff / 100 + 1;

    int firstDivisibleBy400 = y1;
    if (firstDivisibleBy400 % 400 != 0) {
        firstDivisibleBy400 += 400 - (y1 % 400);
    }
    diff = y2 - firstDivisibleBy400 - 1;
    int divisibleBy400 = diff < 0 ? 0 : diff / 400 + 1;

    return divisibleBy4 - divisibleBy100 + divisibleBy400;
}


public static Calendar from(Date date) {

    Calendar c = Calendar.getInstance();
    c.setTime(date);

    return c;
}


public static Calendar removeTime(Calendar c) {

    c.set(HOUR_OF_DAY, 0);
    c.set(MINUTE, 0);
    c.set(SECOND, 0);
    c.set(MILLISECOND, 0);

    return c;
}

2

아마도 가장 간단한 방법 일 것입니다. 아마도 내가 자바로 코딩 했으므로 (아마도 날짜와 시간 라이브러리가 있음) 아마도 그 코드가 나에게 "단순하고 멋지게 보입니다"!

결과가 밀리 초 단위로 반환되는 것에 만족합니까, 아니면 다른 형식으로 반환하는 것을 선호하는 질문의 일부입니까?


2

표준 API를 사용하지 않습니다. 다음과 같은 작업을 수행 할 수 있습니다.

class Duration {
    private final TimeUnit unit;
    private final long length;
    // ...
}

또는 Joda 를 사용할 수 있습니다 .

DateTime a = ..., b = ...;
Duration d = new Duration(a, b);

2

초기 질문에 대답하기 위해 :

Long getAge () {}와 같은 함수에 다음 코드를 넣습니다.

Date dahora = new Date();
long MillisToYearsByDiv = 1000l *60l * 60l * 24l * 365l;
long javaOffsetInMillis = 1990l * MillisToYearsByDiv;
long realNowInMillis = dahora.getTime() + javaOffsetInMillis;
long realBirthDayInMillis = this.getFechaNac().getTime() + javaOffsetInMillis;
long ageInMillis = realNowInMillis - realBirthDayInMillis;

return ageInMillis / MillisToYearsByDiv;

여기서 가장 중요한 것은 곱하고 나눌 때 긴 숫자로 작업하는 것입니다. 그리고 물론, 날짜 계산에 Java가 적용되는 오프셋.

:)


2

질문에 스칼라 태그가 붙어 있기 때문에

import scala.concurrent.duration._
val diff = (System.currentTimeMillis() - oldDate.getTime).milliseconds
val diffSeconds = diff.toSeconds
val diffMinutes = diff.toMinutes
val diffHours = diff.toHours
val diffDays = diff.toDays

2

다른 모든 답변을 넘어 서면 Java 7 Date 유형을 유지하지만 Java 8 diff 접근 방식으로보다 정확하고 표준 적입니다.

public static long daysBetweenDates(Date d1, Date d2) {
    Instant instant1 = d1.toInstant();
    Instant instant2 = d2.toInstant();
    long diff = ChronoUnit.DAYS.between(instant1, instant2);
    return diff;
}

1

이 시도:

int epoch = (int) (new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse("01/01/1970  00:00:00").getTime() / 1000);

parse () 메소드 param에서 문자열을 편집 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.