Java 8: Perbedaan antara dua LocalDateTime dalam beberapa unit

266

Saya mencoba menghitung perbedaan antara dua LocalDateTime .

Keluaran harus dalam format y years m months d days h hours m minutes s seconds . Inilah yang saya tulis:

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;

public class Main {

    static final int MINUTES_PER_HOUR = 60;
    static final int SECONDS_PER_MINUTE = 60;
    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;

    public static void main(String[] args) {
        LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 9, 19, 46, 45);
        LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

        Period period = getPeriod(fromDateTime, toDateTime);
        long time[] = getTime(fromDateTime, toDateTime);

        System.out.println(period.getYears() + " years " + 
                period.getMonths() + " months " + 
                period.getDays() + " days " +
                time[0] + " hours " +
                time[1] + " minutes " +
                time[2] + " seconds.");


    }

    private static Period getPeriod(LocalDateTime dob, LocalDateTime now) {
        return Period.between(dob.toLocalDate(), now.toLocalDate());
    }

    private static long[] getTime(LocalDateTime dob, LocalDateTime now) {
        LocalDateTime today = LocalDateTime.of(now.getYear(),
                now.getMonthValue(), now.getDayOfMonth(), dob.getHour(), dob.getMinute(), dob.getSecond());
        Duration duration = Duration.between(today, now);

        long seconds = duration.getSeconds();

        long hours = seconds / SECONDS_PER_HOUR;
        long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
        long secs = (seconds % SECONDS_PER_MINUTE);

        return new long[]{hours, minutes, secs};
    }
}

Output yang saya dapatkan adalah 29 years 8 months 24 days 12 hours 0 minutes 50 seconds. Saya telah memeriksa hasil saya dari situs web ini (dengan nilai-nilai12/16/1984 07:45:55 dan 09/09/2014 19:46:45). Tangkapan layar berikut menunjukkan output:

Konverter Zaman

Saya cukup yakin bahwa bidang setelah nilai bulan salah dari kode saya. Setiap saran akan sangat membantu.

Memperbarui

Saya telah menguji hasil saya dari situs web lain dan hasil yang saya dapatkan berbeda. Ini dia: Hitung durasi antara dua tanggal (hasil: 29 tahun, 8 bulan, 24 hari, 12 jam, 0 menit dan 50 detik).

Memperbarui

Karena saya mendapat dua hasil berbeda dari dua situs yang berbeda, saya bertanya-tanya apakah algoritma perhitungan saya sah atau tidak. Jika saya menggunakan dua LocalDateTimeobjek berikut :

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

Maka output akan datang: 29 years 8 months 25 days -1 hours -5 minutes -10 seconds.

Dari tautan ini seharusnya29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds . Jadi algoritma perlu menangani angka negatif juga.

Perhatikan pertanyaannya bukan tentang situs mana yang memberi saya hasil apa, saya perlu tahu algoritma yang tepat dan harus memiliki hasil yang benar.

Tapas Bose
sumber
Hanya tebakan, tetapi mungkin Period.between()menerapkan pembulatan?
Thomas
3
Saya hanya melihat kode sekali lagi dan sepertinya situs webnya salah (Coba hitung sendiri). Jika Anda menghilangkan tanggal, yaitu perbedaan dalam tahun, bulan dan hari, Anda akan mendapatkan waktu mulai 7:45:55dan waktu akhir 19:46:45(atau 7:46:45PM). Jadi perbedaan antara kedua waktu itu adalah 12 jam, 0 menit dan 50 detik dan tidak pernah 23 jam, 34 menit dan 12 detik. Jadi perhitungan Anda tampaknya benar, setidaknya pada bagian waktu.
Thomas
1
Fenomena menarik di situs web itu: tambahkan 10 tahun ke tanggal mulai dan perbedaan jam berubah dari 23 menjadi 8 - pasti merupakan tanda bug.
Thomas
8
Perhatikan bahwa karena LocalDateTimetidak memiliki zona waktu, mungkin tidak ada jawaban yang unik. Bahkan jika Anda menganggap zona waktu mulai dan akhir adalah sama, di zona tertentu tanggal seperti 2014-09-09 akan berada di Waktu Musim Panas atau Musim Panas dan di tempat lain tidak. Ini mungkin membuang beberapa jam. Jadi menghitung perbedaan ke yang kedua tidak ada artinya kecuali ini diselesaikan.
Stuart Marks
2
Apakah Anda mengerti bahwa menggunakan LocalDateTimehasil tidak realistis, karena kelas itu sengaja tidak memiliki konsep zona waktu atau offset-dari-UTC? Untuk nilai realistis, tetapkan zona waktu via ZoneIduntuk digunakan ZonedDateTime.
Basil Bourque

Jawaban:

163

Sayangnya, sepertinya tidak ada kelas periode yang mencakup waktu juga, jadi Anda mungkin harus melakukan perhitungan sendiri.

Untungnya, kelas tanggal dan waktu memiliki banyak metode utilitas yang menyederhanakannya sampai tingkat tertentu. Berikut adalah cara untuk menghitung perbedaan meskipun tidak selalu yang tercepat:

LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);

LocalDateTime tempDateTime = LocalDateTime.from( fromDateTime );

long years = tempDateTime.until( toDateTime, ChronoUnit.YEARS );
tempDateTime = tempDateTime.plusYears( years );

long months = tempDateTime.until( toDateTime, ChronoUnit.MONTHS );
tempDateTime = tempDateTime.plusMonths( months );

long days = tempDateTime.until( toDateTime, ChronoUnit.DAYS );
tempDateTime = tempDateTime.plusDays( days );


long hours = tempDateTime.until( toDateTime, ChronoUnit.HOURS );
tempDateTime = tempDateTime.plusHours( hours );

long minutes = tempDateTime.until( toDateTime, ChronoUnit.MINUTES );
tempDateTime = tempDateTime.plusMinutes( minutes );

long seconds = tempDateTime.until( toDateTime, ChronoUnit.SECONDS );

System.out.println( years + " years " + 
        months + " months " + 
        days + " days " +
        hours + " hours " +
        minutes + " minutes " +
        seconds + " seconds.");

//prints: 29 years 8 months 24 days 22 hours 54 minutes 50 seconds.

Ide dasarnya adalah ini: buat tanggal mulai sementara dan dapatkan tahun penuh hingga akhir. Kemudian sesuaikan tanggal dengan jumlah tahun sehingga tanggal mulai kurang dari satu tahun dari akhir. Ulangi itu untuk setiap unit waktu dalam urutan menurun.

Akhirnya penafian : Saya tidak memperhitungkan zona waktu yang berbeda (kedua tanggal harus dalam zona waktu yang sama) dan saya juga tidak menguji / memeriksa bagaimana waktu musim panas atau perubahan lain dalam kalender (seperti perubahan zona waktu di Samoa) mempengaruhi perhitungan ini. Jadi gunakan dengan hati-hati.

Thomas
sumber
1
Anda memiliki ide dasar yang sama, karena itu upvote saya, tetapi silakan coba gunakan input yang sama jika tidak hasil yang berbeda membingungkan.
Meno Hochschild
@MenoHochschild itu adalah input yang sama, baru saja diambil dari pembaruan di mana OP memiliki masalah dengan waktu negatif. ;)
Thomas
1
Algoritma yang baik, tetapi salah ketik (lihat Thomas disclaimer). Sebelum melakukan perhitungan Anda, Anda harus mengubah variabel LocalDateTime Anda ke ZonedDateTime menggunakan zona waktu default misalnya (atau zona waktu apa pun yang Anda butuhkan): ZonedDateTime fromZonedDateTime = fromDateTime.atZone (ZoneId.systemDefault ());
Tristan
2
@ Thomas Contoh Anda menggunakan Java 8 juga - dan pertanyaannya ditandai sebagai java-8. Bahkan contoh Anda bahkan menggunakan ChronoUnit:) tetapi melakukan pekerjaan "dengan tangan".
Eugene Beresovsky
3
@EugeneBeresovsky oh ya, Anda benar. Benar-benar melewatkan itu;) - Selain itu, Anda masih harus mengurangi unit yang lebih besar dari interval karena misalnya long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);akan mengembalikan angka lebih besar dari 59 untuk setiap interval setidaknya 1 jam - dan bukan itu yang diinginkan OP. Dengan mempertimbangkan itu, Anda tidak akan bisa hanya melakukan 6 panggilan ChronoUnit#between()dan selesai.
Thomas
503

Saya menemukan cara terbaik untuk melakukan ini adalah dengan ChronoUnit.

long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);
long hours = ChronoUnit.HOURS.between(fromDate, toDate);

Dokumentasi tambahan ada di sini: https://docs.oracle.com/javase/tutorial/datetime/iso/ period.html

satnam
sumber
8
Saya tidak melihat peningkatan nyata. Dibandingkan dengan jawaban yang diterima Thomas' Anda hanya mengganti tempDateTime.until( toDateTime, ChronoUnit.YEARS)dengan ChronoUnit.YEARS.between(fromDate, toDate). Tetapi baris tambahan penting seperti tempDateTime.plusYears( years )dll benar-benar hilang dalam jawaban Anda sehingga tidak membantu OP. Algoritma lengkap itu penting!
Meno Hochschild
9
Saya suka ini lebih baik karena lebih ringkas, dan lebih mudah dibaca. Ini adalah cara terbaik untuk menemukan perbedaan antara dua tanggal.
Somaiah Kumbera
7
@SomaiahKumbera Tidak, Anda benar-benar kehilangan titik kritis. OP tidak ingin durasi hanya dalam satu unit tetapi banyak unit , dan karena itu jawaban ini sama sekali bukan jawaban nyata. Kekhawatiran OP sama sekali tidak ditangani. Mohon berbaik hati membaca lagi pertanyaannya. (Banyak pemilih tampaknya salah paham pertanyaannya).
Meno Hochschild
125
@MenoHochschild, saya pikir Anda benar-benar kehilangan titik kritis. OP mendapat jawaban mereka lebih dari setahun yang lalu. 36 ribu orang yang melihat pertanyaan ini tidak peduli dengan pertanyaan khusus OP. Mereka dipimpin di sini oleh google dan jawaban saya memberi mereka apa yang mereka cari - solusi bersih dan sederhana untuk mendapatkan perbedaan antara dua tanggal.
satnam
10
Saya membutuhkan perbedaan detik antara dua kali tanggal dan mulai menerapkan solusi saya sendiri. Tak lama tampaknya rumit dan saya mengambil di google. satnam answer mungkin tidak menjawab pertanyaan OP tetapi pasti banyak membantu saya dan saya bertaruh banyak orang lain seperti saya.
Julian
43

Berikut satu contoh menggunakan Duration dan TimeUnit untuk mendapatkan format 'hh: mm: ss'.

Duration dur = Duration.between(localDateTimeIni, localDateTimeEnd);
long millis = dur.toMillis();

String.format("%02d:%02d:%02d", 
        TimeUnit.MILLISECONDS.toHours(millis),
        TimeUnit.MILLISECONDS.toMinutes(millis) - 
        TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
        TimeUnit.MILLISECONDS.toSeconds(millis) - 
        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
Junior Batista
sumber
2
Ini sebenarnya mungkin untuk melakukannya seperti ini: String.format("%02d:%02d:%02d",dur.toHoursPart(), dur.toMinutesPart(), dur.toSecondsPart());. Metode bagian memberi Anda angka yang tepat untuk membangun string. Saya pikir itu lebih mudah dibaca.
Daantie
Catatan untuk komentar saya sebelumnya: metode bagian hanya tersedia dari JDK 9 dan lebih tinggi.
Daantie
40

Itu harus lebih sederhana!

Duration.between(startLocalDateTime, endLocalDateTime).toMillis();
Zon
sumber
1
Saya percaya ini sebenarnya solusi semantik yang benar mulai dari Java 8. Dan sebelum versi itu, JodaTime melakukan hal yang sama.
Vrakfall
9

TL; DR

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

dan kemudian menggunakan metode period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart().


Jawaban diperluas

Saya akan menjawab pertanyaan awal, yaitu bagaimana mendapatkan perbedaan waktu antara dua LocalDateTimestahun, bulan, hari, jam & menit, sehingga "jumlah" (lihat catatan di bawah) dari semua nilai untuk unit yang berbeda sama dengan total perbedaan temporal, dan sedemikian rupa sehingga nilai di setiap unit lebih kecil dari unit yang lebih besar berikutnya — yaitu minutes < 60,hours < 24 dan seterusnya.

Diberi dua LocalDateTimes startdan end, mis

LocalDateTime start = LocalDateTime.of(2019, 11, 29, 17, 15);
LocalDateTime end = LocalDateTime.of(2020, 11, 30, 18, 44);

kita dapat mewakili rentang waktu absolut antara keduanya dengan Duration—mungkin menggunakan Duration.between(start, end). Tetapi unit terbesar yang dapat kita ambil dari a Durationadalah hari (sebagai unit temporal yang setara dengan 24 jam) —lihat catatan di bawah ini untuk penjelasan. Untuk menggunakan unit yang lebih besar (bulan, tahun) kami dapat mewakili ini Durationdengan sepasang ( Period, Duration), di mana Periodmengukur perbedaan hingga presisi hari dan Durationsisanya mewakili:

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

Sekarang kita cukup menggunakan metode yang didefinisikan Perioddan Durationuntuk mengekstrak unit individu:

System.out.printf("%d years, %d months, %d days, %d hours, %d minutes, %d seconds",
        period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(),
        duration.toMinutesPart(), duration.toSecondsPart());
1 years, 0 months, 1 days, 1 hours, 29 minutes, 0 seconds

atau, menggunakan format default:

System.out.println(period + " + " + duration);
P1Y1D + PT1H29M

Perhatikan tahun, bulan & hari

Perhatikan bahwa, dalam java.timekonsepsi, "unit" seperti "bulan" atau "tahun" tidak mewakili nilai temporal absolut yang tetap — bergantung pada tanggal dan kalender, seperti yang diilustrasikan oleh contoh berikut:

LocalDateTime
        start1 = LocalDateTime.of(2020, 1, 1, 0, 0),
        end1 = LocalDateTime.of(2021, 1, 1, 0, 0),
        start2 = LocalDateTime.of(2021, 1, 1, 0, 0),
        end2 = LocalDateTime.of(2022, 1, 1, 0, 0);
System.out.println(Period.between(start1.toLocalDate(), end1.toLocalDate()));
System.out.println(Duration.between(start1, end1).toDays());
System.out.println(Period.between(start2.toLocalDate(), end2.toLocalDate()));
System.out.println(Duration.between(start2, end2).toDays());
P1Y
366
P1Y
365
Anakhand
sumber
5

Ada beberapa masalah untuk kode Tapas Bose dan kode Thomas. Jika perbedaan waktu adalah negatif, array mendapat nilai negatif. Misalnya jika

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);
LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);

ia mengembalikan 0 tahun 0 bulan 1 hari -1 jam 0 menit 0 detik.

Saya pikir output yang tepat adalah: 0 tahun 0 bulan 0 hari 23 jam 0 menit 0 detik.

Saya mengusulkan untuk memisahkan instance LocalDateTime pada instance LocalDate dan LocalTime. Setelah itu kita bisa mendapatkan contoh Periode dan Durasi Java 8. Contoh Durasi dipisahkan pada jumlah hari dan nilai waktu sepanjang hari (<24jam) dengan koreksi selanjutnya dari nilai periode. Ketika nilai LocalTime kedua adalah sebelum nilai firstLocalTime, perlu untuk mengurangi periode selama satu hari.

Inilah cara saya untuk menghitung perbedaan LocalDateTime:

private void getChronoUnitForSecondAfterFirst(LocalDateTime firstLocalDateTime, LocalDateTime secondLocalDateTime, long[] chronoUnits) {
    /*Separate LocaldateTime on LocalDate and LocalTime*/
    LocalDate firstLocalDate = firstLocalDateTime.toLocalDate();
    LocalTime firstLocalTime = firstLocalDateTime.toLocalTime();

    LocalDate secondLocalDate = secondLocalDateTime.toLocalDate();
    LocalTime secondLocalTime = secondLocalDateTime.toLocalTime();

    /*Calculate the time difference*/
    Duration duration = Duration.between(firstLocalDateTime, secondLocalDateTime);
    long durationDays = duration.toDays();
    Duration throughoutTheDayDuration = duration.minusDays(durationDays);
    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Duration is: " + duration + " this is " + durationDays
            + " days and " + throughoutTheDayDuration + " time.");

    Period period = Period.between(firstLocalDate, secondLocalDate);

    /*Correct the date difference*/
    if (secondLocalTime.isBefore(firstLocalTime)) {
        period = period.minusDays(1);
        Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
                "minus 1 day");
    }

    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Period between " + firstLocalDateTime + " and "
            + secondLocalDateTime + " is: " + period + " and duration is: "
            + throughoutTheDayDuration
            + "\n-----------------------------------------------------------------");

    /*Calculate chrono unit values and  write it in array*/
    chronoUnits[0] = period.getYears();
    chronoUnits[1] = period.getMonths();
    chronoUnits[2] = period.getDays();
    chronoUnits[3] = throughoutTheDayDuration.toHours();
    chronoUnits[4] = throughoutTheDayDuration.toMinutes() % 60;
    chronoUnits[5] = throughoutTheDayDuration.getSeconds() % 60;
}

Metode di atas dapat digunakan untuk menghitung selisih nilai tanggal dan waktu setempat, misalnya:

public long[] getChronoUnits(String firstLocalDateTimeString, String secondLocalDateTimeString) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    LocalDateTime firstLocalDateTime = LocalDateTime.parse(firstLocalDateTimeString, formatter);
    LocalDateTime secondLocalDateTime = LocalDateTime.parse(secondLocalDateTimeString, formatter);

    long[] chronoUnits = new long[6];
    if (secondLocalDateTime.isAfter(firstLocalDateTime)) {
        getChronoUnitForSecondAfterFirst(firstLocalDateTime, secondLocalDateTime, chronoUnits);
    } else {
        getChronoUnitForSecondAfterFirst(secondLocalDateTime, firstLocalDateTime, chronoUnits);
    }
    return chronoUnits;
}

Lebih mudah menulis unit test untuk metode di atas (keduanya adalah anggota kelas PeriodDuration). Ini kodenya:

@RunWith(Parameterized.class)
public class PeriodDurationTest {

private final String firstLocalDateTimeString;
private final String secondLocalDateTimeString;
private final long[] chronoUnits;

public PeriodDurationTest(String firstLocalDateTimeString, String secondLocalDateTimeString, long[] chronoUnits) {
    this.firstLocalDateTimeString = firstLocalDateTimeString;
    this.secondLocalDateTimeString = secondLocalDateTimeString;
    this.chronoUnits = chronoUnits;
}

@Parameters
public static Collection<Object[]> periodValues() {
    long[] chronoUnits0 = {0, 0, 0, 0, 0, 0};
    long[] chronoUnits1 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits2 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits3 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits4 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits5 = {0, 0, 1, 23, 0, 0};
    long[] chronoUnits6 = {29, 8, 24, 12, 0, 50};
    long[] chronoUnits7 = {29, 8, 24, 12, 0, 50};
    return Arrays.asList(new Object[][]{
        {"2015-09-09 21:46:44", "2015-09-09 21:46:44", chronoUnits0},
        {"2015-09-09 21:46:44", "2015-09-09 22:46:44", chronoUnits1},
        {"2015-09-09 21:46:44", "2015-09-10 20:46:44", chronoUnits2},
        {"2015-09-09 21:46:44", "2015-09-09 20:46:44", chronoUnits3},
        {"2015-09-10 20:46:44", "2015-09-09 21:46:44", chronoUnits4},
        {"2015-09-11 20:46:44", "2015-09-09 21:46:44", chronoUnits5},
        {"1984-12-16 07:45:55", "2014-09-09 19:46:45", chronoUnits6},
        {"2014-09-09 19:46:45", "1984-12-16 07:45:55", chronoUnits6}
    });
}

@Test
public void testGetChronoUnits() {
    PeriodDuration instance = new PeriodDuration();
    long[] expResult = this.chronoUnits;
    long[] result = instance.getChronoUnits(this.firstLocalDateTimeString, this.secondLocalDateTimeString);
    assertArrayEquals(expResult, result);
}

}

Semua tes berhasil apakah nilai LocalDateTime pertama adalah sebelum dan untuk nilai-nilai LocalTime.

Gennady Kolomoets
sumber
Saya tidak dapat mereproduksi pernyataan Anda bahwa kode Thomas menggunakan input Anda di atas menghasilkan tanda-tanda campuran. Output saya adalah: "0 tahun 0 bulan 0 hari 23 jam 0 menit 0 detik.". Dan saya telah menguji sekarang.
Meno Hochschild
Terima kasih atas komentarnya. Saya benar-benar menguji kode Thomas, memang, itu berfungsi dengan benar! Keajaiban ini dilakukan oleh LocalDateTime hingga metode mengoreksi unit chrono. Nilai negatif dalam kode Thomas muncul jika DateTime pertama lebih lambat dari yang kedua. Tetapi ini dapat dengan mudah diperbaiki, misalnya, seperti yang saya lakukan pada kode di atas. Terima kasih lagi.
Gennady Kolomoets
Nah, kode Thomas dan pustaka saya Time4J menggunakan algoritma yang sama untuk perhitungan durasi dapat menghasilkan tanda-tanda negatif tetapi hanya untuk seluruh durasi. Itu adalah poin penting! Tanda terkait dengan seluruh durasi dan karenanya menjelaskan jika awal lebih lambat dari akhir dan tidak pernah terkait dengan komponen durasi tunggal. Tanda-tanda campuran tidak dimungkinkan di sini dan akan mencegah penafsiran awal relatif terhadap akhir (contoh berlawanan adalah Joda-Time-periode atau di java.time.Periodmana pengguna dapat menegakkan / membuat tanda-tanda campuran tersebut karena desain internal yang berbeda).
Meno Hochschild
5

Dan versi @Thomas di Groovy dengan mengambil unit yang diinginkan dalam daftar alih-alih nilai hardcoding. Implementasi ini (yang dapat dengan mudah porting ke Java - saya membuat deklarasi fungsi eksplisit) membuat pendekatan Thomas lebih dapat digunakan kembali.

def fromDateTime = LocalDateTime.of(1968, 6, 14, 0, 13, 0)
def toDateTime = LocalDateTime.now()
def listOfUnits = [
    ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS,
    ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS,
    ChronoUnit.MILLIS]

println calcDurationInTextualForm(listOfUnits, fromDateTime, toDateTime)    

String calcDurationInTextualForm(List<ChronoUnit> listOfUnits, LocalDateTime ts, LocalDateTime to)
{
    def result = []

    listOfUnits.each { chronoUnit ->
        long amount = ts.until(to, chronoUnit)
        ts = ts.plus(amount, chronoUnit)

        if (amount) {
            result << "$amount ${chronoUnit.toString()}"
        }
    }

    result.join(', ')
}

Pada saat penulisan ini, kode di atas kembali 47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis. Dan, untuk input @Gennady Kolomoets, kode kembali 23 Hours.

Ketika Anda memberikan daftar unit, itu harus diurutkan berdasarkan ukuran unit (terbesar pertama):

def listOfUnits = [ChronoUnit.WEEKS, ChronoUnit.DAYS, ChronoUnit.HOURS]
// returns 2495 Weeks, 3 Days, 8 Hours
ChrLipp
sumber
4

Inilah jawaban yang sangat sederhana untuk pertanyaan Anda. Berhasil.

import java.time.*;
import java.util.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class MyClass {
public static void main(String args[]) {
    DateTimeFormatter T = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
    Scanner h = new Scanner(System.in);

    System.out.print("Enter date of birth[dd/mm/yyyy hh:mm]: ");
    String b = h.nextLine();

    LocalDateTime bd = LocalDateTime.parse(b,T);
    LocalDateTime cd = LocalDateTime.now();

    long minutes = ChronoUnit.MINUTES.between(bd, cd);
    long hours = ChronoUnit.HOURS.between(bd, cd);

    System.out.print("Age is: "+hours+ " hours, or " +minutes+ " minutes old");
}
}
DisimpanBeau
sumber
1
Saya harus menyebutkan ini tidak akurat. coba dengan ini. katanya perbedaan 1 menit. LocalDateTime bd = LocalDateTime.of (2019, 11, 26, 15, 03, 55); LocalDateTime cd = LocalDateTime.of (2019, 11, 26, 15, 04, 45);
Mark Amabile
Saya memasuki waktu semalam dan mendapat Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old. Saya tidak berpikir inilah yang diinginkan.
Ole VV
@ OleV.V. Memperbaiki masalah itu
SavedBeau
1

Joda-Time

Karena banyak jawaban yang diperlukan dukungan API 26 dan API min saya adalah 23, saya menyelesaikannya dengan kode di bawah ini:

import org.joda.time.Days

LocalDate startDate = Something
LocalDate endDate = Something
// The difference would be exclusive of both dates, 
// so in most of use cases we may need to increment it by 1
Days.daysBetween(startDate, endDate).days
Kushal
sumber
1
Proyek Joda-Time berada dalam mode pemeliharaan, penciptanya Stephen Colebourne telah menciptakan kelas java.time yang didefinisikan dalam JSR 310. Sebagian besar fungsi java.time di -port- backing ke Java 6 & 7 di ThreeTen- Proyek backport . Lebih lanjut diadaptasi untuk Android awal dalam proyek ThreeTenABP .
Basil Bourque
1

Setelah lebih dari lima tahun saya menjawab pertanyaan saya. Saya pikir masalah dengan durasi negatif dapat diselesaikan dengan koreksi sederhana:

LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);

Period period = Period.between(fromDateTime.toLocalDate(), toDateTime.toLocalDate());
Duration duration = Duration.between(fromDateTime.toLocalTime(), toDateTime.toLocalTime());

if (duration.isNegative()) {
    period = period.minusDays(1);
    duration = duration.plusDays(1);
}
long seconds = duration.getSeconds();
long hours = seconds / SECONDS_PER_HOUR;
long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
long secs = (seconds % SECONDS_PER_MINUTE);
long time[] = {hours, minutes, secs};
System.out.println(period.getYears() + " years "
            + period.getMonths() + " months "
            + period.getDays() + " days "
            + time[0] + " hours "
            + time[1] + " minutes "
            + time[2] + " seconds.");

Catatan: Situs https://www.epochconverter.com/date-difference sekarang menghitung perbedaan waktu dengan benar.

Terima kasih atas diskusi dan saran Anda.

Gennady Kolomoets
sumber
Terima kasih atas jawabannya. Untuk berjam-jam dan lebih kecil Anda bisa mendapat manfaat dari toHours, toMinutesdan toSecondsmetode Duration. Sejak Java 9 bahkan lebih dari toMinutesPart()dan toSecondsPart(). Dan saya tidak melihat titik dalam membungkus jam, menit dan detik menjadi array hanya untuk mengeluarkannya lagi. Umumnya jawaban yang bagus.
Ole VV
Setelah lebih dari lima tahun saya menjawab pertanyaan saya. Pertanyaannya diposting dari akun dengan nama, judul, dan lokasi yang berbeda, sepertinya tidak banyak kemiripan? Bukannya itu penting, hanya ingin tahu.
Ole VV
"Setelah lebih dari lima tahun saya menjawab pertanyaan saya" Saya kira saya adalah OP :)
Tapas Bose