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:
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 LocalDateTime
objek 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.
Period.between()
menerapkan pembulatan?7:45:55
dan waktu akhir19:46:45
(atau7:46:45
PM). 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.LocalDateTime
tidak 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.LocalDateTime
hasil tidak realistis, karena kelas itu sengaja tidak memiliki konsep zona waktu atau offset-dari-UTC? Untuk nilai realistis, tetapkan zona waktu viaZoneId
untuk digunakanZonedDateTime
.Jawaban:
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:
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.
sumber
ChronoUnit
:) tetapi melakukan pekerjaan "dengan tangan".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 panggilanChronoUnit#between()
dan selesai.Saya menemukan cara terbaik untuk melakukan ini adalah dengan ChronoUnit.
Dokumentasi tambahan ada di sini: https://docs.oracle.com/javase/tutorial/datetime/iso/ period.html
sumber
tempDateTime.until( toDateTime, ChronoUnit.YEARS)
denganChronoUnit.YEARS.between(fromDate, toDate)
. Tetapi baris tambahan penting sepertitempDateTime.plusYears( years )
dll benar-benar hilang dalam jawaban Anda sehingga tidak membantu OP. Algoritma lengkap itu penting!Berikut satu contoh menggunakan Duration dan TimeUnit untuk mendapatkan format 'hh: mm: ss'.
sumber
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.Itu harus lebih sederhana!
sumber
TL; DR
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
LocalDateTimes
tahun, 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 — yaituminutes < 60
,hours < 24
dan seterusnya.Diberi dua
LocalDateTimes
start
danend
, miskita dapat mewakili rentang waktu absolut antara keduanya dengan
Duration
—mungkin menggunakanDuration.between(start, end)
. Tetapi unit terbesar yang dapat kita ambil dari aDuration
adalah 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 iniDuration
dengan sepasang (Period
,Duration
), di manaPeriod
mengukur perbedaan hingga presisi hari danDuration
sisanya mewakili:Sekarang kita cukup menggunakan metode yang didefinisikan
Period
danDuration
untuk mengekstrak unit individu:atau, menggunakan format default:
Perhatikan tahun, bulan & hari
Perhatikan bahwa, dalam
java.time
konsepsi, "unit" seperti "bulan" atau "tahun" tidak mewakili nilai temporal absolut yang tetap — bergantung pada tanggal dan kalender, seperti yang diilustrasikan oleh contoh berikut:sumber
Ada beberapa masalah untuk kode Tapas Bose dan kode Thomas. Jika perbedaan waktu adalah negatif, array mendapat nilai negatif. Misalnya jika
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:
Metode di atas dapat digunakan untuk menghitung selisih nilai tanggal dan waktu setempat, misalnya:
Lebih mudah menulis unit test untuk metode di atas (keduanya adalah anggota kelas PeriodDuration). Ini kodenya:
}
Semua tes berhasil apakah nilai LocalDateTime pertama adalah sebelum dan untuk nilai-nilai LocalTime.
sumber
java.time.Period
mana pengguna dapat menegakkan / membuat tanda-tanda campuran tersebut karena desain internal yang berbeda).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.
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 kembali23 Hours
.Ketika Anda memberikan daftar unit, itu harus diurutkan berdasarkan ukuran unit (terbesar pertama):
sumber
Inilah jawaban yang sangat sederhana untuk pertanyaan Anda. Berhasil.
sumber
Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old
. Saya tidak berpikir inilah yang diinginkan.Joda-Time
Karena banyak jawaban yang diperlukan dukungan API 26 dan API min saya adalah 23, saya menyelesaikannya dengan kode di bawah ini:
sumber
Setelah lebih dari lima tahun saya menjawab pertanyaan saya. Saya pikir masalah dengan durasi negatif dapat diselesaikan dengan koreksi sederhana:
Catatan: Situs https://www.epochconverter.com/date-difference sekarang menghitung perbedaan waktu dengan benar.
Terima kasih atas diskusi dan saran Anda.
sumber
toHours
,toMinutes
dantoSeconds
metodeDuration
. Sejak Java 9 bahkan lebih daritoMinutesPart()
dantoSecondsPart()
. Dan saya tidak melihat titik dalam membungkus jam, menit dan detik menjadi array hanya untuk mengeluarkannya lagi. Umumnya jawaban yang bagus.