FYI, format yang tampaknya Anda gambarkan adalah sebuah Durationdefinisi dalam standar yang masuk akal, ISO 8601 : di PnYnMnDTnHnMnSmana Pberarti "Periode" dan menandai awal, Tmemisahkan bagian tanggal dari bagian waktu, dan di antaranya adalah kemunculan opsional angka dengan satu singkatan huruf. Misalnya, PT4H30M= empat setengah jam.
Basil Bourque
1
Jika semuanya gagal, itu masalah yang sangat sederhana untuk melakukannya sendiri. Cukup gunakan aplikasi yang berurutan dari %dan /untuk membagi nomor menjadi beberapa bagian. Hampir lebih mudah daripada beberapa jawaban yang diajukan.
Hot Licks
@HotLicks Serahkan pada metode perpustakaan untuk kode yang lebih bersih dan lebih jelas daripada menggunakan /dan %.
Ole VV
Ya, dalam selang waktu 8 tahun sejak saya mengajukan pertanyaan ini (!) Saya telah pindah ke waktu joda yang sangat sesuai dengan kasus penggunaan saya
phatmanace
@phatmanace Proyek Joda-Time sekarang dalam mode pemeliharaan, dan menyarankan migrasi ke kelas java.time dibangun ke dalam Java 8 dan yang lebih baru.
Tampaknya dari jawaban di bawah ini bahwa instance Periode dapat dibuat secara langsung, tanpa terlebih dahulu membuat instance Duration dan kemudian mengubahnya menjadi Periode. Misalnya Periode periode = Periode baru (milis); String formatted = formatter.print (titik);
Basil Vandegriend tanggal
7
Waspadalah terhadap konversi "durasi.toPeriod ()" ini. Jika durasinya cukup besar, porsi hari dan seterusnya akan tetap 0. Porsi jam akan terus bertambah. Anda akan mendapatkan 25h10m23s tetapi tidak pernah mendapatkan "d". Alasannya adalah tidak ada cara yang sepenuhnya benar untuk mengubah jam menjadi hari dengan cara yang ketat dari Joda. Sebagian besar kasus, jika Anda membandingkan dua instan dan ingin mencetaknya, Anda dapat melakukan Periode baru (t1, t2) alih-alih Durasi baru (t1, t2) .toPeriod ().
Boon
@Boon, apakah Anda tahu cara mengubah durasi ke periode sehubungan dengan hari? Saya menggunakan durasi dari mana saya bisa mengganti detik di timer saya. Pengaturan acara PeriodType.daysTime()atau .standard()tidak membantu
murt
4
@murt Jika Anda benar-benar ingin, dan dapat menerima definisi standar hari, maka Anda dapat "formatter.print (durasi.toPeriod (). normalizedStandard ())" dalam kode di atas. Selamat bersenang-senang!
Boon
77
Saya telah membangun solusi sederhana, menggunakan Java 8 Duration.toString()dan sedikit regex:
Anda tidak boleh mengandalkan output toStrong () karena ini dapat berubah di versi selanjutnya.
Weltraumschaf
14
@Weltraumschaf itu tidak mungkin berubah, karena itu ditentukan dalam javadoc
aditsu berhenti karena SE JAHAT
9
@Weltraumschaf Kemungkinan tidak berubah karena keluaran dari Duration::toStringdiformat sesuai dengan standar ISO 8601 yang ditentukan dengan baik dan sudah usang .
Basil Bourque
1
Jika Anda tidak menginginkan pecahan, tambahkan .replaceAll("\\.\\d+", "")sebelum panggilan ke toLowerCase().
zb226
1
@Weltraumschaf Poin Anda secara umum benar dan saya sendiri tidak akan bergantung pada output toString () dari sebagian besar kelas. Tetapi dalam kasus yang sangat spesifik ini, definisi metode menyatakan bahwa outputnya mengikuti standar ISO-8601, seperti yang Anda lihat di Javadoc metode . Jadi ini bukan detail implementasi seperti di kebanyakan kelas, oleh karena itu bukan sesuatu yang saya harapkan bahasa yang matang seperti Java berubah seperti itu,
lucasls
13
Apache commons-lang menyediakan kelas yang berguna untuk menyelesaikannya juga DurationFormatUtils
JodaTime memiliki Periodkelas yang dapat mewakili kuantitas seperti itu, dan dapat dirender (melalui IsoPeriodFormat) dalam format ISO8601 , mis.PT4D1H3M5S , mis.
Period period = new Period(millis);
String formatted = ISOPeriodFormat.standard().print(period);
Jika format itu bukan yang Anda inginkan, maka PeriodFormatterBuildermemungkinkan Anda menyusun tata letak sewenang-wenang, termasuk gaya C # Anda 4d1h3m5s.
Proyek ThreeTen-Extra , yang dikelola oleh Stephen Colebourne, penulis JSR 310, java.time , dan Joda-Time , memiliki AmountFormatskelas yang bekerja dengan kelas waktu tanggal 8 Java standar. Ini cukup bertele-tele, tanpa opsi untuk output yang lebih kompak.
Duration d = Duration.ofMinutes(1).plusSeconds(9).plusMillis(86);
System.out.println(AmountFormats.wordBased(d, Locale.getDefault()));
Wow, senang mengetahuinya, saya belum melihat fitur itu. Namun memiliki satu kelemahan utama: Kehilangan koma Oxford .
Basil Bourque
4
@BasilBourque Koma Oxford adalah tipikal untuk AS, tetapi menariknya tidak untuk Inggris. Lib Time4J saya (yang memiliki internasionalisasi yang jauh lebih baik) mendukung perbedaan ini di kelas net.time4j.PrettyTime dan juga memungkinkan kontrol atas keluaran ringkas jika diinginkan.
Bagaimana Anda mendapatkan "toHoursPart" dan yang lebih baru?
Ghoti dan Chips
5
Sebuah alternatif untuk pendekatan pembangun dari Joda-Waktu akan menjadi solusi berbasis pola . Ini ditawarkan oleh perpustakaan saya Time4J . Contoh menggunakan kelas Duration.Formatter (menambahkan beberapa spasi agar lebih mudah dibaca - menghapus spasi akan menghasilkan gaya C # yang diinginkan):
IsoUnit unit = ClockUnit.MILLIS;
Duration<IsoUnit> dur = // normalized duration with multiple components
Duration.of(123456, unit).with(Duration.STD_PERIOD);
Duration.Formatter<IsoUnit> f = // create formatter/parser with optional millis
Duration.Formatter.ofPattern("D'd' h'h' m'm' s[.fff]'s'");
System.out.println(f.format(dur)); // output: 0d 0h 2m 3.456s
Pemformat ini juga dapat mencetak durasi java.time-API (namun, fitur normalisasi jenis itu kurang kuat):
Perkiraan OP bahwa "123456 ms sepanjang akan dicetak sebagai 4d1h3m5s" dihitung dengan cara yang jelas salah. Saya menganggap kecerobohan sebagai alasan. Pemformat durasi yang sama yang ditentukan di atas juga dapat digunakan sebagai parser. Kode berikut menunjukkan bahwa "4d1h3m5s" agak sesuai dengan 349385000 = 1000 * (4 * 86400 + 1 * 3600 + 3 * 60 + 5):
Cara lain adalah menggunakan kelas net.time4j.PrettyTime(yang juga bagus untuk keluaran yang dilokalkan dan mencetak waktu relatif seperti "kemarin", "Minggu depan", "4 hari yang lalu", dll.):
String s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.NARROW);
System.out.println(s); // output: 2m 3s 456ms
s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.WIDE);
System.out.println(s); // output: 2 minutes, 3 seconds, and 456 milliseconds
s = PrettyTime.of(Locale.UK).print(dur, TextWidth.WIDE);
System.out.println(s); // output: 2 minutes, 3 seconds and 456 milliseconds
Kontrol lebar teks apakah singkatan digunakan atau tidak. Format daftar juga dapat dikontrol dengan memilih lokal yang sesuai. Misalnya, bahasa Inggris standar menggunakan koma Oxform, sedangkan Inggris tidak. Versi terbaru v5.5 dari Time4J mendukung lebih dari 90 bahasa dan menggunakan terjemahan berdasarkan repositori CLDR (standar industri).
PrettyTime ini jauh lebih baik daripada yang ada di jawaban lain! Sayang sekali saya tidak menemukan ini dulu.
ycomp
Saya tidak tahu mengapa sekarang ada dua suara negatif untuk solusi yang berfungsi dengan baik ini jadi saya telah memutuskan untuk memperluas jawaban dengan memberikan lebih banyak contoh juga tentang penguraian (kebalikan dari pemformatan) dan untuk menyoroti harapan OP yang salah.
@erickdeoliveiraleal Terima kasih telah menunjukkannya. Saya rasa saya awalnya menulis kode untuk groovy, jadi itu mungkin berhasil dalam bahasa itu. Saya mengoreksinya untuk java sekarang.
Torsten
3
Saya menyadari ini mungkin tidak sesuai dengan kasus penggunaan Anda, tetapi PrettyTime mungkin berguna di sini.
PrettyTime p = new PrettyTime();
System.out.println(p.format(new Date()));
//prints: “right now”
System.out.println(p.format(new Date(1000*60*10)));
//prints: “10 minutes from now”
Duration
definisi dalam standar yang masuk akal, ISO 8601 : diPnYnMnDTnHnMnS
manaP
berarti "Periode" dan menandai awal,T
memisahkan bagian tanggal dari bagian waktu, dan di antaranya adalah kemunculan opsional angka dengan satu singkatan huruf. Misalnya,PT4H30M
= empat setengah jam.%
dan/
untuk membagi nomor menjadi beberapa bagian. Hampir lebih mudah daripada beberapa jawaban yang diajukan./
dan%
.Jawaban:
Joda Time memiliki cara yang cukup bagus untuk melakukan ini menggunakan PeriodFormatterBuilder .
Menang cepat:
PeriodFormat.getDefault().print(duration.toPeriod());
misalnya
//import org.joda.time.format.PeriodFormatter; //import org.joda.time.format.PeriodFormatterBuilder; //import org.joda.time.Duration; Duration duration = new Duration(123456); // in milliseconds PeriodFormatter formatter = new PeriodFormatterBuilder() .appendDays() .appendSuffix("d") .appendHours() .appendSuffix("h") .appendMinutes() .appendSuffix("m") .appendSeconds() .appendSuffix("s") .toFormatter(); String formatted = formatter.print(duration.toPeriod()); System.out.println(formatted);
sumber
PeriodType.daysTime()
atau.standard()
tidak membantuSaya telah membangun solusi sederhana, menggunakan Java 8
Duration.toString()
dan sedikit regex:public static String humanReadableFormat(Duration duration) { return duration.toString() .substring(2) .replaceAll("(\\d[HMS])(?!$)", "$1 ") .toLowerCase(); }
Hasilnya akan terlihat seperti:
- 5h - 7h 15m - 6h 50m 15s - 2h 5s - 0.1s
Jika Anda tidak ingin spasi di antaranya, hapus saja
replaceAll
.sumber
Duration::toString
diformat sesuai dengan standar ISO 8601 yang ditentukan dengan baik dan sudah usang ..replaceAll("\\.\\d+", "")
sebelum panggilan ketoLowerCase()
.Apache commons-lang menyediakan kelas yang berguna untuk menyelesaikannya juga DurationFormatUtils
misal
DurationFormatUtils.formatDurationHMS( 15362 * 1000 ) )
=> 4: 16: 02.000 (H: m: s.millis)DurationFormatUtils.formatDurationISO( 15362 * 1000 ) )
=> P0Y0M0DT4H16M2.000S, lih. ISO8601sumber
JodaTime memiliki
Period
kelas yang dapat mewakili kuantitas seperti itu, dan dapat dirender (melaluiIsoPeriodFormat
) dalam format ISO8601 , mis.PT4D1H3M5S
, mis.Period period = new Period(millis); String formatted = ISOPeriodFormat.standard().print(period);
Jika format itu bukan yang Anda inginkan, maka
PeriodFormatterBuilder
memungkinkan Anda menyusun tata letak sewenang-wenang, termasuk gaya C # Anda4d1h3m5s
.sumber
new Period(millis).toString()
gunakanISOPeriodFormat.standard()
secara default.Dengan Java 8 Anda juga dapat menggunakan
toString()
metodejava.time.Duration
untuk memformatnya tanpa pustaka eksternal menggunakan representasi berbasis ISO 8601 detik seperti PT8H6M12.345S.sumber
Inilah cara Anda melakukannya menggunakan kode JDK murni:
import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; long diffTime = 215081000L; Duration duration = DatatypeFactory.newInstance().newDuration(diffTime); System.out.printf("%02d:%02d:%02d", duration.getDays() * 24 + duration.getHours(), duration.getMinutes(), duration.getSeconds());
sumber
org.threeten.extra.AmountFormats.wordBased
Proyek ThreeTen-Extra , yang dikelola oleh Stephen Colebourne, penulis JSR 310, java.time , dan Joda-Time , memiliki
AmountFormats
kelas yang bekerja dengan kelas waktu tanggal 8 Java standar. Ini cukup bertele-tele, tanpa opsi untuk output yang lebih kompak.Duration d = Duration.ofMinutes(1).plusSeconds(9).plusMillis(86); System.out.println(AmountFormats.wordBased(d, Locale.getDefault()));
1 minute, 9 seconds and 86 milliseconds
sumber
Java 9+
Duration d1 = Duration.ofDays(0); d1 = d1.plusHours(47); d1 = d1.plusMinutes(124); d1 = d1.plusSeconds(124); System.out.println(String.format("%s d %sh %sm %ss", d1.toDaysPart(), d1.toHoursPart(), d1.toMinutesPart(), d1.toSecondsPart()));
2 d 1j 6m 4s
sumber
Sebuah alternatif untuk pendekatan pembangun dari Joda-Waktu akan menjadi solusi berbasis pola . Ini ditawarkan oleh perpustakaan saya Time4J . Contoh menggunakan kelas Duration.Formatter (menambahkan beberapa spasi agar lebih mudah dibaca - menghapus spasi akan menghasilkan gaya C # yang diinginkan):
IsoUnit unit = ClockUnit.MILLIS; Duration<IsoUnit> dur = // normalized duration with multiple components Duration.of(123456, unit).with(Duration.STD_PERIOD); Duration.Formatter<IsoUnit> f = // create formatter/parser with optional millis Duration.Formatter.ofPattern("D'd' h'h' m'm' s[.fff]'s'"); System.out.println(f.format(dur)); // output: 0d 0h 2m 3.456s
Pemformat ini juga dapat mencetak durasi
java.time
-API (namun, fitur normalisasi jenis itu kurang kuat):System.out.println(f.format(java.time.Duration.ofMillis(123456))); // output: 0d 0h 2m 3.456s
Perkiraan OP bahwa "123456 ms sepanjang akan dicetak sebagai 4d1h3m5s" dihitung dengan cara yang jelas salah. Saya menganggap kecerobohan sebagai alasan. Pemformat durasi yang sama yang ditentukan di atas juga dapat digunakan sebagai parser. Kode berikut menunjukkan bahwa "4d1h3m5s" agak sesuai dengan
349385000 = 1000 * (4 * 86400 + 1 * 3600 + 3 * 60 + 5)
:System.out.println( f.parse("4d 1h 3m 5s") .toClockPeriodWithDaysAs24Hours() .with(unit.only()) .getPartialAmount(unit)); // 349385000
Cara lain adalah menggunakan kelas
net.time4j.PrettyTime
(yang juga bagus untuk keluaran yang dilokalkan dan mencetak waktu relatif seperti "kemarin", "Minggu depan", "4 hari yang lalu", dll.):String s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.NARROW); System.out.println(s); // output: 2m 3s 456ms s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.WIDE); System.out.println(s); // output: 2 minutes, 3 seconds, and 456 milliseconds s = PrettyTime.of(Locale.UK).print(dur, TextWidth.WIDE); System.out.println(s); // output: 2 minutes, 3 seconds and 456 milliseconds
Kontrol lebar teks apakah singkatan digunakan atau tidak. Format daftar juga dapat dikontrol dengan memilih lokal yang sesuai. Misalnya, bahasa Inggris standar menggunakan koma Oxform, sedangkan Inggris tidak. Versi terbaru v5.5 dari Time4J mendukung lebih dari 90 bahasa dan menggunakan terjemahan berdasarkan repositori CLDR (standar industri).
sumber
Versi Java 8 berdasarkan jawaban pengguna678573 :
private static String humanReadableFormat(Duration duration) { return String.format("%s days and %sh %sm %ss", duration.toDays(), duration.toHours() - TimeUnit.DAYS.toHours(duration.toDays()), duration.toMinutes() - TimeUnit.HOURS.toMinutes(duration.toHours()), duration.getSeconds() - TimeUnit.MINUTES.toSeconds(duration.toMinutes())); }
... karena tidak ada PeriodFormatter di Java 8 dan tidak ada metode seperti getHours, getMinutes, ...
Saya akan senang melihat versi yang lebih baik untuk Java 8.
sumber
Saya menyadari ini mungkin tidak sesuai dengan kasus penggunaan Anda, tetapi PrettyTime mungkin berguna di sini.
PrettyTime p = new PrettyTime(); System.out.println(p.format(new Date())); //prints: “right now” System.out.println(p.format(new Date(1000*60*10))); //prints: “10 minutes from now”
sumber