İki Java tarih örneği arasındaki farkın hesaplanması


433

java.util.DateScala'da Java'nın sınıfını kullanıyorum ve bir Datenesneyi ve şimdiki zamanı karşılaştırmak istiyorum . GetTime () kullanarak delta hesaplayabilirsiniz biliyorum:

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

Ancak, bu beni longtemsil eden milisaniye bırakıyor . Zaman deltası almanın daha basit ve daha güzel bir yolu var mı?


10
Neden joda zamanı sevgisi yok? Java ile tarihlerle uğraşacaksanız hemen hemen en iyi seçenek.
Doktor Jones

7
Lütfen Joda kullanmadan ve stackoverflow.com/a/10650881/82609
Sebastien Lorber


2
@ Zizouz212 Joda-Time'ı tavsiye etmekle ilgili olarak, Java ile birlikte gelen eski tarih-saat sınıfları kötü, gerçek kötü, kötü tasarlanmış, kafa karıştırıcı ve zahmetlidir. Öyle kötü ki, Joda-Time onların yerine geçtikçe çok başarılı oldu. O kadar kötü ki, Sun / Oracle bile onlardan vazgeçti ve Java 8 ve üstü paketlerin bir parçası olarak java.time paketini benimsedi. Java.time sınıfları Joda-Time'dan esinlenmiştir. Hem Joda-Time hem de java.time aynı adam Stephen Colbourne tarafından yönetiliyor . Ben derdim “kimseye yazıklar kullanımını öneren Date, Calendarve SimpleDateFormat”.
Basil Bourque

2
Joda Time, soru sorulduğunda muhtemelen iyi bir cevap olsa da, bugün Java 8'i kullanabilen herkes için en iyi cevap java.time.Periodve / veya kullanmaktır Duration. Bkz aşağıda Basil Bourque cevabını .
Ole VV

Yanıtlar:


198

JDK DateAPI maalesef korkunç bir şekilde bozuldu. Joda Time kütüphanesini kullanmanızı tavsiye ederim .

Joda Zaman zaman kavramını vardır aralığı :

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

DÜZENLEME: Bu arada, Joda'nın iki kavramı vardır: Intervaliki zaman örneği arasında bir zaman aralığını temsil etmek için (08: 00-10: 00 arasındaki zamanı temsil eder) ve a Duration, gerçek zaman sınırları olmayan bir süreyi temsil eder (örneğin iki saati temsil eder!)

Yalnızca zaman karşılaştırmalarına önem veriyorsanız, çoğu Dateuygulama (JDK biri dahil) Comparable,Comparable.compareTo()


btw - demek istiyorsun Comparable.compareTo(), değil Comparable.compare().
Scott Morrison

Joda-Time, bir süreyi çeşitli şekillerde tasvir etmek için üç sınıfa sahiptir: Aralık, Süre ve Dönem. Bu doğru cevap bu ilk ikisini tartışıyor. Bkz Cevabımı Dönemi hakkında bilgi için.
Basil Bourque

Java 8'in joda gibi yeni bir tarih ve saati vardır.
tbodt

11
java.timeJava 8'deki yeni paket Joda-Time'dan esinlenilmiştir, ancak yedek bir yedek değildir. Her birinin artıları ve eksileri vardır. Neyse ki bunlar arasında seçim yapmak zorunda değilsiniz. importİfadelerinize dikkat ettiğiniz sürece her birini güçlü yönleri için kullanın . Bkz bu diğer cevabını java.time örneğin.
Basil Bourque

6
FYI, Joda-Time projesi şu anda bakım modunda ve ekip java.time sınıflarına geçişi tavsiye ediyor . Oracle'ın Öğreticisine bakın .
Basil Bourque

550

Basit fark (lib olmadan)

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

Sonra arayabilirsin:

getDateDiff(date1,date2,TimeUnit.MINUTES);

dakika cinsinden 2 tarihin farkını elde etmek için.

TimeUnitolduğu java.util.concurrent.TimeUnitgünlere Nano giden standart bir Java enum.


İnsan tarafından okunabilir fark (lib olmadan)

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

Çıktı, Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}sipariş edilen birimlerle benzer bir şeydir .

Bu haritayı kullanıcı dostu bir dizeye dönüştürmeniz yeterlidir.


Uyarı

Yukarıdaki kod parçacıkları 2 örnek arasında basit bir fark hesaplar. Bu yazıda açıklandığı gibi, gün ışığından yararlanma anahtarı sırasında sorunlara neden olabilir . Bu, tarihler arasındaki farkı hiçbir zaman olmadan hesaplarsanız eksik bir gün / saatiniz olabileceği anlamına gelir.

Bence tarih farkı, özellikle günlerde subjektiftir. Yapabilirsin:

  • geçen 24 saat sayısını sayın: gün + 1 - gün = 1 gün = 24 saat

  • gün ışığından yararlanma tasarrufuna dikkat ederek geçen süreyi sayın: gün + 1 - gün = 1 = 24 saat (ancak gece yarısı ve gün ışığından yararlanma saatlerini kullanarak 0 gün 23 saat olabilir)

  • sayısını day switches(: p gün ışığından olup olmadığını ya da 1 H) geçen zaman sadece 2 saat olsa bile, günlük 11:00 = 1 gün - gün + 1 1:00 anlamına gelir,

Cevabım, tarih tanımınız günlere göre değişiyorsa 1. durumla eşleşiyorsa geçerlidir

JodaTime ile

JodaTime kullanıyorsanız, 2 örnek için (milli destekli ReadableInstant) tarihler ile farkı alabilirsiniz:

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

Ancak Yerel tarihler / saatler için farkı alabilirsiniz:

// 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()

Vay canına, gerçekten yaşlı bir köpeğe yeni numaralar öğretebilirsiniz! Bunu daha önce hiç duymadım, tarih farklılıklarını anlamlı dizelere çevirmek için çok yararlı.
Jeremy Goodell

@SebastienLorber TimeUnit'te farkı hesaplamanın bir yolu var mı? "Alarm 3 gün, 4 saat ve 12 dakika sonra ayarlanmıştır".
likejudo

parlak şeyler gerçekten çok zamanımı kurtardı. Yardımınıza minnettar olurum.
Lyju I Edwinson

Java Dates ile uğraşan hayatımın 3 gününü boşa harcadım ve sadece birçoğunu attım ve onunla değiştirdim. Teşekkür ederim.
user1091524

Bu stackoverflow geldiğimden beri gördüğüm en iyi cevap! : D: D: D
Soğuk

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

Bunun UTC tarihleriyle çalıştığını unutmayın, bu nedenle yerel tarihlere bakarsanız fark bir günlük izin olabilir. Ve yerel tarihlerle doğru şekilde çalışmasını sağlamak, yaz saati uygulaması nedeniyle tamamen farklı bir yaklaşım gerektirir.


6
Bu aslında Android'de düzgün çalışmıyor. Yuvarlama hataları var. Örnek 19-21 Mayıs, 1 gün diyor, çünkü 1.99 ila 1 yayınlıyor.
Pratik Mandrekar

4
Bu en iyi ve en basit cevap. İki tarih arasındaki bir farkı hesaplarken, yerel saat dilimleri birbirini çıkarır ... böylece doğru cevap (çift olarak) basitçe ((double) (newer.getTime () - eski.getTime ()) / (86400.0 * 1000.0); ... bir çift olarak, HH: MM: ss'ye kolayca dönüştürülebilen kesirli bir gününüz var
scottb

8
@scottb: yerel tarihlerle ilgili sorun, gün ışığından yararlanma süresine sahip olmanızdır, bu da bazı günlerde 23 veya 25 saatin olması ve muhtemelen sonucu bozması anlamına gelir.
Michael Borgwardt

1
@Steve: Bu yeni Tarih gibi tanımlarken benim için 28 (115, 2, 26); (parametreler için API dokümanına dikkat edin). 26/03/2015 tarihini 2015'in 26. ayının 3. günü olarak yorumlayabilmek için ABD tarih biçimini ve yumuşak modda ayrıştırmanız mümkün mü?
Michael Borgwardt

1
@Steve: hm, neden daha önce farklı bir sonuç aldığımdan emin değilim, ama şimdi hatanızı yeniden oluşturabilirim. Kodunuzdaki parantez neden benim cevap, daha farklıdır (endDate.getTime() - startDate.getTime())için döküm olmak intyerine nihai sonucun ve bir tamsayı taşması alıyoruz.
Michael Borgwardt

54

Java 8+ üzerine yerleşik java.time çerçevesini kullanarak :

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

Çıktı:

ISO-8601: PT24H10M

Dakika: 1450

Daha fazla bilgi için Oracle Tutorial ve ISO 8601 standardına bakın.


5
Bu, veya tarih Periodyerine kullanın Duration.
Aphex

53

Sorununuzu daha açık bir şekilde tanımlamanız gerekir. Sen olabilir sadece iki arasındaki milisaniye sayısını almak Date, örneğin 24 saat içinde milisaniye sayısına göre nesneler ve böl ... ama:

  • Bu, zaman dilimlerini dikkate almayacak - Dateher zaman UTC'de
  • Bu, yaz saati uygulamasını dikkate almaz (örneğin, yalnızca 23 saat uzunluğundaki günler olabilir)
  • UTC içinde bile, 16 Ağustos 23:00 ile 18 Ağustos 02:00 arasında kaç gün var? Sadece 27 saat, bu bir gün demek mi? Yoksa üç günü kapsaması nedeniyle üç gün olmalı mı?

1
Java.util diye düşündüm. Tarih, yerel (varsayılan) saat diliminde yorumlanan, zaman milisli bir temsil etrafında küçük bir paketleyiciydi. Bir Tarih basmak bana yerel bir saat dilimi temsili verir. Burada kafam karıştı mı?
Adriaan Koster

46

tl; Dr.

Eskimiş java.util.Datenesnelerini onların yerine dönüştür java.time.Instant. Sonra geçen süreyi a olarak hesaplayın 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 Biçimi: PnYnMnDTnHnMnS

Mantıklı standart ISO 8601 tanımlar birkaç yıl gibi uzun bir zaman dilimi bir kısa metin gösterimi, ay, gün, saat, vb standart çağrılar, örneğin bir yayılma bir süre . Biçimdir PnYnMnDTnHnMnSnerede Pvasıta "Dönem", Tzaman kısmından tarih bölümünü ayırır ve bir harf tarafından takip sayılardır arasında.

Örnekler:

  • P3Y6M4DT12H30M5S
    üç yıl, altı ay, dört gün, on iki saat, otuz dakika ve beş saniye
  • PT4H30M
    Dört buçuk saat

java.time

Java.time sonra Java 8 yerleşik ve çerçeve zahmetli eski yerine alır java.util.Date/ java.util.Calendarsınıfları. Yeni sınıflar , halefi olarak düşünülen, konseptte benzer ancak yeniden tasarlanmış , son derece başarılı Joda-Time çerçevesinden ilham alıyor . JSR 310 tarafından tanımlanmıştır . ThreeTen-Extra projesi ile genişletildi . Eğiticiye bakın .

An

InstantSınıfı zaman çizelgesinde bir anı temsil UTC çözünürlüğe sahip nanosaniye (ondalık kesir dokuz (9) haneye kadar).

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

Date/ Gibi eski sınıflardan kaçınmak en iyisidir Calendar. Ancak, java.time için henüz güncellenmemiş eski kodlarla birlikte çalışmanız gerekiyorsa , ileri geri dönüş yapın. Eski sınıflara eklenen yeni dönüşüm yöntemlerini çağırın. A 'dan a' ya java.util.Dategeçmek için Instantarayın Date::toInstant.

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

Zaman aralığı

Java.time sınıfları, bir süreyi birkaç yıl, ay, gün, saat, dakika, saniye olarak temsil etme fikrini iki yarıya bölmüştür:

  • Period yıllarca, aylarca, günlerce
  • Duration günler, saatler, dakikalar, saniyeler için

İşte bir örnek.

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

Konsola dökümü.

Her ikisi de Periodve değerlerinin bir String temsilini oluşturmak Durationiçin ISO 8601 standardını kullanır .

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

şimdi: 2015-11-26T00: 46: 48.016-05: 00 [Amerika / Montreal] gelecek: 2015-11-26T00: 46: 48.016-05: 00 [Amerika / Montreal] = PT1H3M

Java 9 Duration, gün bölümü, saat bölümü, dakika bölümü ve saniye bölümü almak için yöntemler ekler .

Tüm Süre boyunca toplam gün veya saat veya dakika veya saniye veya milisaniye veya nanosaniye alabilirsiniz.

long totalHours = duration.toHours();

Java 9'da Durationsınıf gün, saat, dakika, saniye, milisaniye / nanosaniyenin çeşitli bölümlerini döndürmek için yeni yöntemler alır . to…PartYöntemleri çağırın : toDaysPart(),, toHoursPart()vb.

ChronoUnit

“Geçen gün sayısı” gibi yalnızca daha basit bir ayrıntı düzeyini önemsiyorsanız, numarayı kullanın ChronoUnit.

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

Başka bir örnek.

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

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

120


Java.time hakkında

Java.time çerçevesi daha sonra Java 8 ve yerleşiktir. Bu sınıflar zahmetli eski yerini mirası gibi tarih-saat sınıfları java.util.Date, Calendar& SimpleDateFormat.

Artık bakım modunda olan Joda-Time projesi java.time'a geçişi tavsiye ediyor.

Daha fazla bilgi için Oracle Eğiticisine bakın . Ve birçok örnek ve açıklama için Stack Overflow'da arama yapın. Spesifikasyon JSR 310'dur .

Java.time sınıflarını nereden edinebilirsiniz?

ThreeTen-Ekstra proje ek sınıfları ile java.time uzanır. Bu proje, java.time'a gelecekteki olası eklemeler için bir kanıt zeminidir. Aşağıdaki gibi burada bazı yararlı sınıfları bulabilir Interval, YearWeek,YearQuarter , ve daha .


Joda-Time

GÜNCELLEME: Joda-Time projesi artık bakım modunda ve ekip java.time sınıflarına geçişi tavsiye ediyor . Bu bölümü tarih için olduğu gibi bırakıyorum.

Joda-Time kütüphanesi, varsayılan değerleri için ISO 8601 kullanır. OnunPeriod sınıf ayrıştırır ve bu PnYnMnDTnHnMnS dizeleri üretir.

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

çizer:

period: PT4H30M

"Tl; dr" ile alakasız bir metin duvarı başlattığınız çok komik. Soru, X'den önce veya X zaman biriminde zaman damgasını nasıl alacağınız değil, iki tarih arasındaki deltanın nasıl elde edileceği ile ilgili değil. Bu kadar.
Buffalo

@Buffalo Yorumunuzu anlamıyorum. Benim Cevap içerir Period, Durationve ChronoUnit, amacı üç sınıfları zaman noktaları arasında delta belirlemektir. Lütfen "metin duvarımın" hangi bölümlerinin alakasız olduğunu belirtin. Ve Sorunun “tarihler arasındaki delta” için sorulduğunu söylemeniz yanlış: Soru Date, söz konusu sınıfın talihsiz isimlendirmesine rağmen “tarihler” değil, tarih-zaman anları olan nesneler arasında bir delta istemiştir .
Basil Bourque

Yorumunuzda mevcut iki java.util.Date nesnesini işleyen hiçbir şey yok. Kodumdaki çeşitli parçacıkları kullanmayı denedim ve java.util.Date nesnesini kullanan hiçbir şey bulamadım.
Buffalo

@Buffalo Yeterince adil, iyi eleştiri. Ben java.util.Datebir Instant(sadece çağrı .toInstant) dönüştürme "tl; dr" bölümünde kod ekledi . Açıklamak için Momentbölümü ekledim . Bir çift Datenesneden bahsettiniz , ama aslında Soru sadece tek bir mevcut Datenesne kullanıyor ve sonra mevcut anı yakalıyor, bu yüzden aynısını yaptım. Geri dönüşünüz için teşekkür ederiz! İpucu: Kullanmaktan vazgeç Date- Bu eski sınıflar gerçekten berbat bir karmaşa.
Basil Bourque


23

Biraz daha basit bir alternatif:

System.currentTimeMillis() - oldDate.getTime()

"Güzel" gelince: Peki, tam olarak neye ihtiyacınız var? Zaman sürelerini birkaç saat ve gün vb. Olarak göstermeyle ilgili sorun, tarihlerin karmaşıklığı nedeniyle yanlışlıklara ve yanlış beklentilere yol açabilmesidir (örneğin, gün ışığından yararlanma saati nedeniyle günler 23 veya 25 saat sürebilir).


22

Milisaniye yaklaşımının kullanılması bazı bölgelerde sorunlara neden olabilir.

Örneğin, 03/24/2007 ve 03/25/2007 tarihleri ​​arasındaki farkı 1 gün alalım;

Ancak, milisaniye rotasını kullanarak, bunu İngiltere'de çalıştırırsanız, 0 gün alacaksınız!

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

Bunu uygulamanın en iyi yolu java.util.Calendar kullanmaktır

/** 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
Bu kodun asıl yazarını ve blog girişi 2007'ye dayanan üçüncü cümleyi lütfen değerlendirebilir misiniz ?
wchargin

Biraz etkisiz değil mi?
Gangnus

Doğru çalışmıyor. daysBetween (yeni GregorianCalendar (2014,03,01), yeni GregorianCalendar (2014,04,02))); 31 döndürür ve 32 döndürmelidir: timeanddate.com/date/…
marcolopes

5
@marcolopes - Yanılıyorsunuz - çünkü takvim ayları sıfır tabanlıdır. Eminim mart / nisan anlam ediyoruz, ama ne olduğunuz test etme özelliği gibi güvenli yazma olmak 31. olan Nisan / Haziran olduğunu -> Yeni GregorianCalendar (2014, Calendar.MARCH, 1) ....
Iroh Amca

@ UncleIroh, haklısın! Bu önemli gerçeği kaçırdım (takvim ayları sıfır tabanlıdır). Bu soruyu tekrar gözden geçirmem gerekiyor.
marcolopes

22

Tarihler ve saatler arasındaki farkı bulmanın birçok yolu vardır. Bildiğim en basit yollardan biri:

      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 deyimi sadece bir örnektir - istediğiniz şekilde biçimlendirebilirsiniz.


5
@ manoj kumar bardhan: taşma yığınına hoş geldiniz: Gördüğünüz gibi soru ve cevaplar yaşında. Cevabınız Soru / Cevap'a mevcut olanlardan daha fazlasını eklemelidir.
Jayan

3
Bir DST geçişi nedeniyle 23 veya 25 saati olan günler ne olacak?
Joni

19

Buradaki tüm cevaplar doğru olduğundan, ancak eski java veya joda veya benzeri gibi üçüncü taraf kütüphanelerini kullandığından, yeni kullanarak başka bir yol bırakacağım , Java 8 ve sonraki sürümlerde java.time sınıflarını bırakacağım . Bkz. Oracle Eğitimi .

Kullanın LocalDateve ChronoUnit:

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

(Başka yayınında açıklandığı gibi), ancak milisaniye eserlerinde tarihleri çıkarılınca var senin tarihlerin zaman parçalarını temizlerken, HOUR_OF_DAY değil SAAT kullanmak:

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
Bu, standart kitaplıkların dışına çıkmadan iki takvim tarihi arasındaki farkı belirlemek için en iyi yöntemdir. Diğer cevapların çoğu, bir günü 24 saatlik keyfi bir süre olarak görür. Artık saniyeler eklenmek yerine çıkarılsaydı, kesin hesaplama MSPERDAY sayısının katlarından biraz daha az olabileceğinden, son hesaplama kesilme nedeniyle biri tarafından kapatılabilir.
JulianSymes

8

JodaTime veya benzerini kullanmak istemiyorsanız, en iyi çözüm muhtemelen şudur:

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

Günlük ms sayısı her zaman aynı değildir (gün ışığından yararlanma saati ve artık saniye nedeniyle), ancak çok yakındır ve en azından gün ışığından yararlanma süresinden kaynaklanan sapmalar daha uzun süreler boyunca iptal edilir. Bu nedenle, bölme ve yuvarlama doğru bir sonuç verecektir (en azından kullanılan yerel takvim DST ve artık saniye dışında garip zaman atlamaları içermediği sürece).

Bunun hâlâ bunu varsaydığını date1ve date2günün aynı saatine ayarlandığını unutmayın. Günün farklı saatlerinde, önce Jon Skeet'in işaret ettiği gibi, "tarih farkı" nın ne anlama geldiğini tanımlamanız gerekir.


Sorun içindedir date1.getTime()vs date2.getTime(). Bu nedenle, 2016-03-03 ile 2016-03-31 arasındaki fark 28 gün, 27 gün hesaplayacaktır.
malat

@malat: Üzgünüm, takip edemem. Ben sadece denedim - kodumu ile 2016-03-03 2016-03-31 farklı 28 gün hesaplar. Örneğinizde başka bir şey hesaplıyorsa, bunu ayrı bir soru olarak sormayı düşünün.
sleske

Ayrıca, uyarımı okudun mu? "bu hala tarih1 ve tarih2'nin günün aynı saatine ayarlandığını varsayar". Testinizde günün farklı saatlerini kullandınız mı?
sleske

Ah doğru ! Math.round()'Gerçek dünya' takvimlerinde güvenli görünen hileyi kaçırdım . Gürültü için üzgünüm.
malat

8

Java için geliştirilmiş bir Tarih / Saat API'sı olan ve Scala ile iyi çalışması gereken Joda Time'a bir göz atın .


Java 8'de java.time (JSR-310) ile değiştirildi
malat

5

Joda Aralığı ve Günler arasındaki farkı göstereyim:

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 Gün 03h 42m 07s" gibi biçimlendirilmiş bir döndürme Dizesi gerekiyorsa şunu deneyin:

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
Whoa, Joda-Time daha önceden yazılmış ve hata ayıklanmış olan Period sınıfını sağladığında neden kendi toplantınızı devredesiniz?
Basil Bourque

8
Neden sadece 32 satır kod gerektiğinde sıkıştırılmış bir dosya boyutu 4.1 MB olan bir kütüphane indirip projeme eklemeliyim?
Ingo

1
Çünkü Joda-Time patates cipsi gibidir: sadece bir tane yiyemezsin. Her yerde Joda-Time kullanacaksınız. Ve Joda-Time iyi test edilmiş ve iyi giyilmiş bir kod olduğu için. Ve Joda-Time bu değerleri serileştirmek veya raporlamak için kullanışlı olabilecek standart ISO 8601 Süre dizelerini ayrıştırdığı ve ürettiği için. Ve Joda-Time, bu değerlerin yerelleştirilmiş temsillerini yazdırmak için biçimlendiriciler içerdiğinden.
Basil Bourque

Tüm kodlarınız test edilmemiştir. stdyukarıda tanımlanmamıştır.
Basil Bourque

@Basil Bourque: İpucu için teşekkürler. Kaynağı düzelttim. Bu hata çeviriden İngilizceye geldi.
Ingo

5

Not: startDate ve endDates -> java.util.Date şeklindedir.

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

ve bitiş tarihi

Günlere benzer şekilde saat, dakika ve saniye de alabilirsiniz

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

4

Buradaki örneği kontrol edin http://www.roseindia.net/java/beginners/DateDifferent.shtml Bu örnek size gün, saat, dakika, saniye ve mili saniye cinsinden fark verir :).

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 örnekleri UTC saatlerinden türetilmedikçe bu yanlıştır. Jon Skeet'in cevabına bakın.
sleske

4

Takvim'in bir örneğini almak için GMT saat dilimini kullanın, Takvim sınıfının set yöntemini kullanarak saati ayarlayın. GMT saat diliminde 0 ofseti (gerçekten önemli değil) ve yaz saati uygulaması yanlış olarak ayarlanmıştır.

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

Milisaniye kısmını sıfırlamayı unutmayın, eski sınıflar java.util.Datevb . Bağlamında iyi bir cevaptır. Saat dilimini GMT'ye ayarlamak için hack'i kullanmak, kodu yaz saati efektleri için duyarsız hale getirir.
Meno Hochschild

4

Aşağıdaki kod size istenen çıktıyı verebilir:

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
Kodunuzun tam olarak ne yaptığını açıklayabilir misiniz? Soru bir zaman deltası soruyor gibi görünüyor ve ilk bakışta kodunuz bir gün deltası döndürüyor gibi görünüyor mu?
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 örnekleri UTC saatlerinden türetilmedikçe bu yanlıştır. Jon Skeet'in cevabına bakın.
sleske

5
@sleske haklı değilsin. Zaman dilimi bilgilerini kullanarak zaten kaybetti Date, bu nedenle bu karşılaştırma, koşullar göz önüne alındığında elde edilebilecek en iyisidir.
Bozho

1
Tamam, sanırım ikimiz de haklıyız. Date örneğinin nereden geldiğine bağlı olduğu doğrudur. Yine de, belirtilmesi gereken yaygın bir hatadır.
sleske

Çözümünüzü kullandığımda şöyle diyor: Tür uyumsuzluğu: uzuntan int'e dönüştürülemiyor. Ben de döküm eklemeniz gerektiğini düşünüyorum ya da bir şey eksik mi?
Reklam Infinitum

3

Yapılacak en iyi şey

(Date1-Date2)/86 400 000 

Bu sayı bir gün içindeki milisaniye sayısıdır .

Bir tarih diğer tarih size milisaniye cinsinden fark verir.

Cevabı çift değişkente toplayın .


Evet neden olmasın? Sorunun nedenini bazı açılardan anlamıyorum: OP'nin ms'de bir farkı var ... ve bir günde belirli sayıda ms var (mavi ayda bir kez belirli astronomik ayarlarla tamam, ancak OP astronomların ihtiyaç duyduğu kadar hassas olması gerektiğini söyleme ...)
mike kemirgen

3

İşte O (1) 'de herhangi bir bağımlılık olmadan doğru bir Java 7 çözümü.

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

Muhtemelen bunu yapmanın en basit yolu - belki de bir süredir Java'da kodlama yapıyorum (açıkçası tıknaz tarih ve saat kütüphaneleriyle), ama bu kod bana "basit ve güzel" görünüyor!

Sonucun milisaniye içinde döndürülmesinden memnun musunuz veya sorunuzun alternatif bir biçimde döndürülmesini tercih ettiğiniz bir parçası mı?


2

Standart API kullanmamak, hayır. Kendinizi şu şekilde yapabilirsiniz:

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

Veya Joda'yı kullanabilirsiniz :

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

2

Sadece ilk soruyu cevaplamak için:

Aşağıdaki kodu Long getAge () {} gibi bir Fonksiyona yerleştirin

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;

Burada en önemlisi çarpma ve bölme işlemlerinde uzun sayılarla çalışmaktır. Ve elbette, Java'nın Tarih hesabında uyguladığı ofset.

:)


2

Soru Scala ile etiketlendiğinden,

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

Diğer tüm yanıtları geçtikten sonra, Java 7 Tarih türünü korumak, ancak Java 8 diff yaklaşımıyla daha kesin / standart olmak için,

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

bunu dene:

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

dizeyi parse () yöntemleri parametresinde düzenleyebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.