Menghitung perbedaan antara dua instance tanggal Java

433

Saya menggunakan java.util.Datekelas Java di Scala dan ingin membandingkan Dateobjek dan waktu saat ini. Saya tahu saya bisa menghitung delta dengan menggunakan getTime ():

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

Namun, ini hanya membuat saya longmewakili milidetik. Apakah ada cara yang lebih sederhana dan lebih bagus untuk mendapatkan waktu delta?

pr1001
sumber
10
Mengapa tidak ada cinta untuk waktu joda? Ini cukup banyak pilihan terbaik jika Anda akan berurusan dengan tanggal di java.
Dokter Jones
7
Silakan periksa solusi 2 liner elegan saya, tanpa menggunakan Joda dan memberikan hasilnya dalam TimeUnit di stackoverflow.com/a/10650881/82609
Sebastien Lorber
2
Malu pada semua orang yang merekomendasikan waktu Joda, dan tidak merekomendasikan jawaban Java yang benar ...
Zizouz212
2
@ Zizouz212 Mengenai merekomendasikan Joda-Time, kelas tanggal-waktu lama yang dibundel dengan Java adalah buruk, sangat buruk, tidak dirancang dengan baik, membingungkan, dan menyusahkan. Sangat buruk sehingga Joda-Time menjadi sangat sukses sebagai pengganti mereka. Sangat buruk bahkan Sun / Oracle menyerah pada mereka, dan mengadopsi paket java.time sebagai bagian dari Java 8 dan yang lebih baru. Kelas java.time terinspirasi oleh Joda-Time. Baik Joda-Time dan java.time dipimpin oleh orang yang sama, Stephen Colbourne . Saya akan mengatakan, “Malu pada siapa pun merekomendasikan penggunaan Date, Calendardan SimpleDateFormat”.
Basil Bourque
2
Sementara Joda Time mungkin merupakan jawaban yang baik ketika pertanyaan itu diajukan, hari ini jawaban terbaik bagi siapa saja yang dapat menggunakan Java 8 adalah menggunakan java.time.Perioddan / atau Duration. Lihat jawaban Basil Bourque di bawah ini .
Ole VV

Jawaban:

198

DateSayangnya, API JDK rusak parah. Saya sarankan menggunakan perpustakaan Joda Time .

Joda Time memiliki konsep Interval waktu :

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

EDIT: Omong-omong, Joda memiliki dua konsep: Intervaluntuk mewakili interval waktu antara dua instance waktu (mewakili waktu antara 8 pagi dan 10 pagi), dan Durationyang mewakili panjang waktu tanpa batas waktu yang sebenarnya (misalnya, mewakili dua jam!)

Jika Anda hanya peduli tentang perbandingan waktu, sebagian besar Dateimplementasi (termasuk JDK satu) mengimplementasikan Comparableantarmuka yang memungkinkan Anda untuk menggunakanComparable.compareTo()

tidak ada
sumber
btw - maksudmu Comparable.compareTo(), tidak Comparable.compare().
Scott Morrison
Joda-Time memiliki tiga kelas untuk menggambarkan rentang waktu dengan berbagai cara: Interval, Durasi, dan Periode. Jawaban yang benar ini membahas dua yang pertama ini. Lihat jawaban saya untuk info tentang Periode.
Basil Bourque
Java 8 memiliki api tanggal dan waktu baru seperti joda.
tbodt
11
java.timePaket baru di Java 8 terinspirasi oleh Joda-Time tetapi bukan pengganti drop-in. Masing-masing memiliki pro dan kontra. Untungnya Anda tidak harus memilih di antara mereka. Gunakan masing-masing untuk kekuatannya selama Anda berhati-hati dengan importpernyataan Anda . Lihat jawaban lain ini sebagai contoh java.time.
Basil Bourque
6
FYI, proyek Joda-Time sekarang dalam mode pemeliharaan , dengan tim menyarankan migrasi ke kelas java.time . Lihat Tutorial oleh Oracle .
Basil Bourque
550

Dif sederhana (tanpa 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);
}

Dan kemudian Anda dapat menelepon:

getDateDiff(date1,date2,TimeUnit.MINUTES);

untuk mendapatkan perbedaan dari 2 tanggal dalam satuan menit.

TimeUnitadalah java.util.concurrent.TimeUnit, enum Java standar yang beralih dari nanos ke hari.


Difabel yang dapat dibaca manusia (tanpa 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

Outputnya seperti Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}, dengan unit yang dipesan.

Anda hanya perlu mengubah peta itu menjadi string yang mudah digunakan.


Peringatan

Cuplikan kode di atas menghitung perbedaan sederhana antara 2 instance. Ini dapat menyebabkan masalah selama sakelar penghematan siang hari, seperti dijelaskan dalam posting ini . Ini berarti jika Anda menghitung perbedaan antara tanggal tanpa waktu Anda mungkin memiliki hari / jam yang hilang.

Menurut pendapat saya, tanggal itu agak subyektif, terutama pada hari-hari tertentu. Kamu boleh:

  • hitung jumlah 24 jam yang telah berlalu: hari + 1 - hari = 1 hari = 24 jam

  • menghitung jumlah waktu yang berlalu, mengurus penghematan siang hari: hari + 1 - hari = 1 = 24 jam (tetapi menggunakan waktu tengah malam dan penghematan siang hari bisa 0 hari dan 23 jam)

  • hitung jumlah day switches, yang berarti hari + 1 1 siang - hari 11 pagi = 1 hari, bahkan jika waktu yang berlalu hanya 2 jam (atau 1 jam jika ada penghematan siang hari: p)

Jawaban saya valid jika definisi tanggal berbeda pada hari sesuai dengan kasus pertama

Dengan JodaTime

Jika Anda menggunakan JodaTime, Anda bisa mendapatkan diff untuk 2 instance (milies didukung ReadableInstant) dengan:

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

Tetapi Anda juga bisa mendapatkan perbedaan untuk tanggal / waktu lokal:

// 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()
Sebastien Lorber
sumber
Wow, Anda benar-benar bisa mengajari anjing tua trik baru! Belum pernah mendengar ini sebelumnya, sangat berguna untuk menerjemahkan perbedaan tanggal menjadi string yang bermakna.
Jeremy Goodell
@SebastienLorber Apakah ada cara di TimeUnit untuk menghitung perbedaannya? "Alarm diatur selama 3 hari, 4 jam, dan 12 menit dari sekarang".
likejudo
hal-hal brilian benar-benar menghemat banyak waktu saya. Hargai bantuan Anda.
Lyju I Edwinson
Saya menghabiskan 3 hari dalam hidup saya berurusan dengan Java Dates dan saya hanya membuang banyak dan mengganti ini. Terima kasih.
user1091524
Ini adalah jawaban terbaik yang pernah saya lihat sejak saya datang di stackoverflow! : D: D: D
Dingin
153
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime()) 
                 / (1000 * 60 * 60 * 24) )

Perhatikan bahwa ini bekerja dengan tanggal UTC, jadi perbedaannya mungkin satu hari libur jika Anda melihat tanggal lokal. Dan membuatnya bekerja dengan benar dengan tanggal lokal memerlukan pendekatan yang sama sekali berbeda karena waktu musim panas.

Michael Borgwardt
sumber
6
Ini sebenarnya tidak berfungsi dengan benar di Android. Ada kesalahan pembulatan. Contoh 19 hingga 21 Mei mengatakan 1 hari karena cast 1,99 ke 1. Gunakan round sebelum casting ke int.
Pratik Mandrekar
4
Ini adalah jawaban terbaik dan paling sederhana. Saat menghitung perbedaan antara dua tanggal, zona waktu lokal saling mengurangi ... sehingga jawaban yang benar (sebagai ganda) diberikan hanya dengan ((dua kali lipat) (lebih baru. GetTime () - older.getTime ()) / (86400.0 * 1000.0); ... sebagai dobel, Anda memiliki hari pecahan juga yang dapat dengan mudah dikonversi ke HH: MM:
dtk
8
@ skottb: masalah dengan tanggal lokal adalah Anda dapat memiliki waktu musim panas, yang berarti beberapa hari memiliki 23 atau 25 jam, berpotensi mengacaukan hasilnya.
Michael Borgwardt
1
@Steve: 28 bagi saya ketika mendefinisikan mereka seperti Tanggal baru ini (115, 2, 26); (perhatikan doc API untuk params). Mungkinkah Anda menguraikannya menggunakan format tanggal AS dan dalam mode ringan, sehingga 26/03/2015 ditafsirkan sebagai hari ke-3 pada bulan ke 26 di tahun 2015?
Michael Borgwardt
1
@Steve: hm, tidak yakin mengapa saya mendapat hasil yang berbeda sebelumnya, tapi sekarang saya bisa mereproduksi kesalahan Anda. Kawat gigi dalam kode Anda berbeda dari pada jawaban saya, yang menyebabkan (endDate.getTime() - startDate.getTime())dilemparkan ke intbukan hasil akhir, dan Anda mendapatkan integer overflow.
Michael Borgwardt
54

Menggunakan kerangka java.time yang ada di dalam Java 8+:

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

Keluaran:

ISO-8601: PT24H10M

Menit: 1450

Untuk info lebih lanjut, lihat Tutorial Oracle dan standar ISO 8601 .

Vitalii Fedorenko
sumber
5
Ini, atau gunakan Periodsebagai ganti Durationtanggal.
Aphex
53

Anda perlu mendefinisikan masalah Anda dengan lebih jelas. Anda bisa mengambil jumlah milidetik di antara dua Dateobjek dan membaginya dengan jumlah milidetik dalam 24 jam, misalnya ... tetapi:

  • Ini tidak akan mempertimbangkan zona waktu - Dateselalu dalam UTC
  • Ini tidak akan mempertimbangkan penghematan waktu siang hari (di mana mungkin ada hari yang hanya 23 jam, misalnya)
  • Bahkan di dalam UTC, ada berapa hari di 16 Agustus 11 malam sampai 18 Agustus 2 pagi? Ini hanya 27 jam, jadi apakah itu berarti satu hari? Atau haruskah itu tiga hari karena mencakup tiga tanggal?
Jon Skeet
sumber
1
Saya pikir java.util. Tanggal hanyalah pembungkus kecil di sekitar representasi milis waktu, ditafsirkan dalam zona waktu lokal (default). Mencetak Tanggal memberi saya representasi zona waktu lokal. Apakah saya bingung di sini?
Adriaan Koster
46

tl; dr

Konversi java.util.Dateobjek usang Anda menjadi pengganti mereka java.time.Instant,. Kemudian hitung waktu yang telah berlalu sebagai a 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

Format ISO 8601: PnYnMnDTnHnMnS

Standar masuk akal ISO 8601 mendefinisikan representasi tekstual singkat dari rentang waktu beberapa tahun, bulan, hari, jam, dll. Panggilan standar seperti rentang durasi . Formatnya adalah di PnYnMnDTnHnMnSmana Pberarti "Periode", yang Tmemisahkan bagian tanggal dari bagian waktu, dan di antaranya adalah angka diikuti oleh huruf.

Contoh:

  • P3Y6M4DT12H30M5S
    tiga tahun, enam bulan, empat hari, dua belas jam, tiga puluh menit, dan lima detik
  • PT4H30M
    Empat setengah jam

waktu java

The java.time kerangka dibangun ke Jawa 8 dan kemudian supplants tua merepotkan java.util.Date/ java.util.Calendarkelas. Kelas-kelas baru terinspirasi oleh kerangka kerja Joda-Time yang sangat sukses , dimaksudkan sebagai penggantinya, serupa dalam konsep tetapi dirancang ulang. Didefinisikan oleh JSR 310 . Diperpanjang oleh proyek ThreeTen-Extra . Lihat Tutorialnya .

Saat

The Instantkelas merupakan saat di timeline di UTC dengan resolusi nanodetik (hingga sembilan (9) angka dari pecahan desimal).

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

Terbaik untuk menghindari kelas warisan seperti Date/ Calendar. Tetapi jika Anda harus beroperasi dengan kode lama yang belum diperbarui ke java.time , konversi bolak-balik. Panggil metode konversi baru yang ditambahkan ke kelas lama. Untuk berpindah dari a java.util.Dateke Instant, panggilan Date::toInstant.

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

Rentang waktu

Kelas java.time telah membagi ide ini mewakili rentang waktu sebagai beberapa tahun, bulan, hari, jam, menit, detik menjadi dua bagian:

  • Period selama bertahun-tahun, berbulan-bulan, berhari-hari
  • Duration selama berhari-hari, berjam-jam, menit, detik

Berikut ini sebuah contoh.

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

Dump ke konsol.

Keduanya Perioddan Durationmenggunakan standar ISO 8601 untuk menghasilkan representasi String dari nilainya.

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

sekarang: 2015-11-26T00: 46: 48.016-05: 00 [Amerika / Montreal] ke masa depan: 2015-11-26T00: 46: 48.016-05: 00 [America / Montreal] = PT1H3M

Java 9 menambahkan metode untuk Durationmendapatkan bagian hari, bagian jam, bagian menit, dan bagian detik.

Anda bisa mendapatkan jumlah total hari atau jam atau menit atau detik atau milidetik atau nanodetik dalam seluruh Durasi.

long totalHours = duration.toHours();

Di Jawa 9 Durationkelas mendapatkan metode baru untuk mengembalikan berbagai bagian hari, jam, menit, detik, milidetik / nanodetik. Memanggil to…Partmetode: toDaysPart(), toHoursPart(), dan sebagainya.

ChronoUnit

Jika Anda hanya peduli dengan rincian waktu yang lebih sederhana, seperti “jumlah hari yang berlalu”, gunakan ChronoUnitenum.

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

Contoh lain.

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

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

120


Tentang java.time

The java.time kerangka dibangun ke Jawa 8 dan kemudian. Kelas-kelas ini menggantikan tua merepotkan warisan kelas tanggal-waktu seperti java.util.Date, Calendar, & SimpleDateFormat.

Proyek Joda-Time , sekarang dalam mode pemeliharaan , menyarankan migrasi ke java.time.

Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasi adalah JSR 310 .

Di mana mendapatkan kelas java.time?

Proyek ThreeTen-Extra memperpanjang java.time dengan kelas tambahan. Proyek ini adalah ajang pembuktian untuk kemungkinan penambahan masa depan ke java.time. Anda mungkin menemukan beberapa kelas berguna di sini seperti Interval, YearWeek, YearQuarter, dan lebih .


Joda-Time

UPDATE: Proyek Joda-Time sekarang dalam mode pemeliharaan , dengan tim menyarankan migrasi ke kelas java.time . Saya membiarkan bagian ini utuh untuk sejarah.

Perpustakaan Joda-Time menggunakan ISO 8601 untuk standarnya. Its Periodmem-parsing kelas dan menghasilkan PnYnMnDTnHnMnS ini string.

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

Memberikan:

period: PT4H30M
Basil Bourque
sumber
Lucu Anda memulai dinding teks yang tidak relevan dengan "tl; dr". Pertanyaannya bukan tentang bagaimana mendapatkan stempel waktu dari X yang lalu atau dalam unit X waktu, tetapi bagaimana cara mendapatkan delta antara dua tanggal. Itu dia.
Buffalo
@Buffalo Saya tidak mengerti komentar Anda. Jawaban saya melibatkan Period,, Durationdan ChronoUnit, tiga kelas yang tujuannya menentukan delta antara titik waktu. Tolong tunjukkan bagian mana dari "dinding teks" saya yang tidak relevan. Dan Anda tidak benar dalam mengatakan Pertanyaannya meminta "delta antara tanggal": Pertanyaan itu meminta delta antara Dateobjek, yang merupakan momen-momen waktu-waktu, bukan "tanggal" meskipun ada nama yang tidak disukai dari kelas itu.
Basil Bourque
Tidak ada dalam komentar Anda yang menangani dua objek java.util.Date yang ada. Saya mencoba menggunakan berbagai potongan dalam kode saya dan tidak menemukan apa pun yang menggunakan objek java.util.Date.
Buffalo
@Buffalo Cukup adil, kritik yang bagus. Saya menambahkan kode di bagian "tl; dr" yang mengubah dari java.util.Dateke Instant(panggilan saja .toInstant). Dan saya menambahkan Momentbagian untuk menjelaskan. Anda menyebutkan sepasang Dateobjek, tetapi sebenarnya Pertanyaan hanya menggunakan satu Dateobjek yang ada dan kemudian menangkap momen saat ini, jadi saya melakukan hal yang sama. Terima kasih untuk umpan baliknya! Kiat: Berhenti menggunakan Date- Kelas-kelas warisan itu benar-benar berantakan.
Basil Bourque
23

Alternatif yang sedikit lebih sederhana:

System.currentTimeMillis() - oldDate.getTime()

Adapun "lebih baik": baik, apa sebenarnya yang Anda butuhkan? Masalah dengan mewakili durasi waktu sebagai jumlah jam dan hari dll adalah bahwa hal itu dapat menyebabkan ketidakakuratan dan ekspektasi yang salah karena kompleksitas tanggal (misalnya hari dapat memiliki 23 atau 25 jam karena waktu musim panas).

Michael Borgwardt
sumber
22

Menggunakan pendekatan milidetik dapat menyebabkan masalah di beberapa lokal.

Mari kita ambil, misalnya, perbedaan antara dua tanggal 03/24/2007 dan 03/25/2007 harus 1 hari;

Namun, menggunakan rute milidetik, Anda akan mendapatkan 0 hari, jika Anda menjalankan ini di Inggris!

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

Cara yang lebih baik untuk mengimplementasikan ini adalah dengan menggunakan 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;  
}  
zasadnyy
sumber
19
Bisakah Anda memberi kredit pada pembuat asli kode ini dan kalimat ketiga, yang entri blognya sudah ada sejak 2007 ?
wchargin
Bukankah ini sedikit tidak efektif?
Gangnus
Itu tidak bekerja dengan benar. daysBetween (GregorianCalendar baru (2014,03,01), GregorianCalendar baru (2014,04,02))); mengembalikan 31, dan seharusnya mengembalikan 32: timeanddate.com/date/…
marcolopes
5
@marcolopes - Anda salah - karena bulan kalender berbasis nol. Saya yakin Anda bermaksud maret / april, tetapi yang Anda uji adalah April / Juni yang 31. Untuk amannya tuliskan seperti -> GregorianCalendar baru (2014, Calendar.MARCH, 1) ....
Paman Iroh
@UncleIroh, Anda benar! Saya melewatkan fakta penting itu (bulan kalender berbasis nol). Saya harus meninjau kembali pertanyaan ini lagi.
marcolopes
22

Ada banyak cara Anda dapat menemukan perbedaan antara tanggal & waktu. Salah satu cara paling sederhana yang saya tahu adalah:

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

Pernyataan cetak hanyalah sebuah contoh - Anda dapat memformatnya, sesuai keinginan Anda.

JDGuide
sumber
5
@ manoj kumar bardhan: selamat datang di stack overflow: Seperti yang Anda lihat, pertanyaan dan jawabannya sudah bertahun-tahun. Jawaban Anda harus menambahkan lebih banyak ke Pertanyaan / Jawaban daripada yang sudah ada.
Jayan
3
Bagaimana dengan hari-hari yang memiliki 23 atau 25 jam karena transisi DST?
Joni
19

Karena semua jawaban di sini benar tetapi menggunakan legacy java atau lib pihak ke-3 seperti joda atau serupa, saya hanya akan membuang cara lain menggunakan kelas java.time baru di Java 8 dan yang lebih baru. Lihat Tutorial Oracle .

Gunakan LocalDatedan 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 );
ΦXocę 웃 Пepeúpa ツ
sumber
9

Mengurangkan tanggal dalam milidetik berfungsi (seperti yang dijelaskan dalam pos lain), tetapi Anda harus menggunakan HOUR_OF_DAY dan bukan HOUR saat membersihkan bagian waktu dari tanggal Anda:

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
}
Malcolm Boekhoff
sumber
1
Ini metode terbaik untuk menentukan perbedaan antara dua tanggal kalender, tanpa pergi ke luar perpustakaan standar. Sebagian besar jawaban lain memperlakukan satu hari sebagai periode 24 jam sewenang-wenang. Jika detik kabisat yang pernah dikurangi daripada ditambahkan, perhitungan akhir bisa dimatikan oleh satu karena pemotongan, karena perbedaan absolut bisa sedikit kurang dari jumlah seluruh kelipatan MSPERDAY.
JulianSymes
8

Jika Anda tidak ingin menggunakan JodaTime atau yang serupa, solusi terbaik mungkin adalah ini:

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

Jumlah ms per hari tidak selalu sama (karena waktu musim panas dan lompatan detik), tetapi sangat dekat, dan setidaknya penyimpangan karena waktu musim panas dibatalkan lebih lama. Karenanya membagi dan kemudian membulatkan akan memberikan hasil yang benar (setidaknya selama kalender lokal yang digunakan tidak mengandung lompatan waktu yang aneh selain DST dan detik kabisat).

Perhatikan bahwa ini masih menganggap itu date1dan date2diatur ke waktu yang sama dalam sehari. Untuk waktu yang berbeda dalam sehari, pertama-tama Anda harus mendefinisikan apa arti "perbedaan tanggal", seperti yang ditunjukkan oleh Jon Skeet.

sleske
sumber
Masalahnya adalah di date1.getTime()vs date2.getTime(). Jadi diffing 2016-03-03 hingga 2016-03-31 akan menghitung 27 hari sementara Anda ingin 28 hari.
malat
@malat: Maaf, saya tidak bisa mengikuti. Saya baru saja mencobanya - diff 2016-03-03 hingga 2016-03-31 dengan kode saya menghitung 28 hari. Jika itu menghitung sesuatu yang lain dalam contoh Anda, pertimbangkan untuk menanyakannya sebagai pertanyaan terpisah.
sleske
Juga, apakah Anda membaca peringatan saya? "Ini masih mengasumsikan bahwa date1 dan date2 diset ke waktu yang sama hari". Apakah Anda mungkin menggunakan waktu yang berbeda dalam ujian?
sleske
Ah benar! Saya melewatkan triknya Math.round(), yang tampaknya aman di kalender 'dunia nyata'. Maaf atas kebisingannya.
malat
8

Lihatlah Joda Time , yang merupakan API Tanggal / Waktu yang ditingkatkan untuk Java dan seharusnya bekerja dengan baik dengan Scala.

Rob H
sumber
digantikan oleh java.time (JSR-310) di Java 8
malat
5

Biarkan saya menunjukkan perbedaan antara Joda Interval dan 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 
pengguna674158
sumber
5

Jika Anda membutuhkan String pengembalian yang diformat seperti "2 Days 03h 42m 07s", coba ini:

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;
}
Ingo
sumber
2
Whoa, mengapa roll sendiri ketika Joda-Time menyediakan kelas Periode yang sudah ditulis dan di-debug?
Basil Bourque
8
Mengapa saya harus mengunduh Perpustakaan dengan FileSize terkompresi sebesar 4,1 MB dan menambahkannya ke Proyek saya, padahal saya hanya perlu 32 Baris kode ???
Ingo
1
Karena Joda-Time seperti keripik kentang: Anda tidak bisa makan hanya satu. Anda akan menggunakan Joda-Time di semua tempat. Dan karena Joda-Time adalah kode yang teruji dan usang. Dan karena Joda-Time mem-parsing dan menghasilkan string Duration ISO 8601 standar yang mungkin berguna untuk membuat cerita bersambung atau melaporkan nilai-nilai ini. Dan karena Joda-Time menyertakan pemformat untuk mencetak representasi lokal dari nilai-nilai ini.
Basil Bourque
Tidak semua kode Anda diuji. stddi atas tidak ditentukan.
Basil Bourque
@ Basil Bourque: Terima kasih atas petunjuknya. Saya telah memilih sumbernya. Kesalahan ini berasal dari terjemahan ke bahasa Inggris.
Ingo
5

Catatan: startDate dan endDate adalah -> 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();

dan tanggal akhir

Mirip dengan hari, Anda juga bisa mendapatkan jam, menit, dan detik

period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();
Shravan Ramamurthy
sumber
4

Lihat contoh di sini http://www.roseindia.net/java/beginners/DateDifferent.shtml Contoh ini memberi Anda perbedaan dalam hari, jam, menit, detik, dan mili detik :).

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.");
    }
}
YoK
sumber
3
-1 Itu salah kecuali turunan Date berasal dari waktu UTC. Lihat jawaban Jon Skeet.
sleske
4

Gunakan zona waktu GMT untuk mendapatkan instance Kalender, atur waktu menggunakan metode atur kelas Kalender. Zona waktu GMT memiliki 0 offset (tidak terlalu penting) dan bendera waktu musim panas disetel ke 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));
Michal
sumber
Jangan lupa untuk nol bagian milidetik yang lain itu adalah jawaban yang baik dalam konteks kelas lama java.util.Datedll. Menggunakan hack untuk mengatur zona waktu ke GMT membuat kode tidak sensitif untuk efek penghematan siang hari.
Meno Hochschild
4

Kode berikut dapat memberi Anda output yang diinginkan:

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());
Vishal Ganjare
sumber
3
Bisakah Anda jelaskan apa yang kode Anda lakukan? Pertanyaannya tampaknya bertanya tentang delta waktu dan, pada pandangan pertama, kode Anda sepertinya mengembalikan delta sehari?
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";
    }
}   
Parth Solanki
sumber
3
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;
Bozho
sumber
5
-1 Itu salah kecuali turunan Date berasal dari waktu UTC. Lihat jawaban Jon Skeet.
sleske
5
@ Sayang kau tidak benar. Dia telah kehilangan informasi zona waktu dengan menggunakan Date, jadi perbandingan ini adalah yang terbaik yang bisa dicapai mengingat keadaan.
Bozho
1
OK, kira kita berdua benar. Memang benar bahwa itu tergantung dari mana instance Date berasal. Tetap saja, itu adalah kesalahan umum sehingga harus disebutkan.
sleske
Ketika saya menggunakan solusi Anda, ia mengatakan: Ketik ketidakcocokan: tidak dapat mengkonversi dari panjang ke int. Saya pikir Anda juga harus menambahkan casting atau apakah saya melewatkan sesuatu?
Ad Infinitum
3

Hal terbaik untuk dilakukan adalah

(Date1-Date2)/86 400 000 

Angka itu adalah jumlah milidetik dalam sehari.

Satu tanggal-tanggal lainnya memberi Anda perbedaan dalam milidetik.

Kumpulkan jawaban dalam variabel ganda .

Revanth Kumar
sumber
Ya kenapa tidak Saya tidak mengerti inti dari pertanyaan dalam beberapa hal: OP memiliki perbedaan dalam ms ... dan ada sejumlah ms dalam satu hari (OK dengan penyesuaian astronomi tertentu sekali dalam bulan biru, tetapi OP tidak dapat mengatakan bahwa itu harus setepat yang diperlukan para astronom ...)
mike rodent
3

Berikut ini adalah solusi Java 7 yang benar di O (1) tanpa ketergantungan apa pun.

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;
}
suxumuxu
sumber
2

Itu mungkin cara paling mudah untuk melakukannya - mungkin itu karena saya telah mengkode di Jawa (dengan perpustakaan tanggal dan waktu yang kukuh) untuk sementara waktu sekarang, tetapi kode itu terlihat "sederhana dan baik" bagi saya!

Apakah Anda senang dengan hasil yang dikembalikan dalam milidetik, atau bagian dari pertanyaan Anda yang Anda inginkan dikembalikan dalam beberapa format alternatif?

Andrzej Doyle
sumber
2

Tidak menggunakan API standar, tidak. Anda dapat melakukan sesuatu sendiri seperti ini:

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

Atau Anda dapat menggunakan Joda :

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

Hanya untuk menjawab pertanyaan awal:

Masukkan kode berikut ke dalam Function seperti 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;

Yang paling penting di sini adalah bekerja dengan angka panjang saat mengalikan dan membagi. Dan tentu saja, offset yang diterapkan Java dalam kalkulus Tanggalnya.

:)

MugiWara No Carlos
sumber
2

Karena pertanyaan ini ditandai dengan Scala,

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
VasiliNovikov
sumber
2

Setelah mengarungi semua jawaban lain, untuk menjaga tipe tanggal Java 7 tetapi lebih tepat / standar dengan pendekatan 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;
}
gen b.
sumber
1

coba ini:

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

Anda dapat mengedit string dalam parameter metode parse ().

sabbibJAVA
sumber