Jawaban:
Jika Anda menggunakan versi Java sebelum 8 ... Anda dapat menggunakan Joda Time dan PeriodFormatter
. Jika Anda benar-benar memiliki durasi (yaitu jumlah waktu yang telah berlalu, tanpa referensi ke sistem kalender) maka Anda mungkin harus menggunakan Duration
sebagian besar - Anda kemudian dapat menelepon toPeriod
(menentukan apa pun yang PeriodType
Anda ingin mencerminkan apakah 25 jam menjadi 1 hari dan 1 jam atau tidak, dll) untuk mendapatkan Period
yang dapat Anda format.
Jika Anda menggunakan Java 8 atau lebih baru: Saya biasanya menyarankan menggunakan java.time.Duration
untuk mewakili durasi. Anda kemudian dapat memanggil getSeconds()
atau sejenisnya untuk mendapatkan bilangan bulat untuk pemformatan string standar sesuai jawaban bobince jika Anda perlu - meskipun Anda harus berhati-hati dengan situasi di mana durasinya negatif, karena Anda mungkin ingin satu tanda negatif pada string output . Jadi sesuatu seperti:
public static String formatDuration(Duration duration) {
long seconds = duration.getSeconds();
long absSeconds = Math.abs(seconds);
String positive = String.format(
"%d:%02d:%02d",
absSeconds / 3600,
(absSeconds % 3600) / 60,
absSeconds % 60);
return seconds < 0 ? "-" + positive : positive;
}
Memformat cara ini cukup sederhana, jika mengganggu manual. Untuk parsing itu menjadi masalah yang lebih sulit secara umum ... Anda masih bisa menggunakan Joda Time bahkan dengan Java 8 jika Anda mau, tentu saja.
Duration
metode s: duration.toHours()
, duration.toMinutesPart()
dan duration.toSecondsPart()
yang tersedia sejak Java 9. Dan untuk mendapatkan nilai absolut dapat menggunakan duration.abs()
.
Jika Anda tidak ingin menyeret pustaka, cukup mudah untuk melakukannya sendiri menggunakan Formatter, atau pintasan terkait misalnya. diberikan jumlah integer detik s:
String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
s/86400, (s%86400)/3600...
berhari-hari jika perlu ...
s > 8640
0 (satu hari): "\u221E"
- infinity
Saya menggunakan DurationFormatUtils dari Apache common seperti:
DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
Ini lebih mudah sejak Java 9. Yang Duration
masih tidak dapat diformat, tetapi metode untuk mendapatkan jam, menit dan detik ditambahkan, yang membuat tugas agak lebih mudah:
LocalDateTime start = LocalDateTime.of(2019, Month.JANUARY, 17, 15, 24, 12);
LocalDateTime end = LocalDateTime.of(2019, Month.JANUARY, 18, 15, 43, 33);
Duration diff = Duration.between(start, end);
String hms = String.format("%d:%02d:%02d",
diff.toHours(),
diff.toMinutesPart(),
diff.toSecondsPart());
System.out.println(hms);
Output dari snippet ini adalah:
24:19:21
long duration = 4 * 60 * 60 * 1000;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
log.info("Duration: " + sdf.format(new Date(duration - TimeZone.getDefault().getRawOffset())));
sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));
sebelum menggunakan format
fungsi.
Ini mungkin semacam peretasan, tetapi ini adalah solusi yang bagus jika seseorang bertekad untuk mencapai ini menggunakan Java 8's java.time
:
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.UnsupportedTemporalTypeException;
public class TemporalDuration implements TemporalAccessor {
private static final Temporal BASE_TEMPORAL = LocalDateTime.of(0, 1, 1, 0, 0);
private final Duration duration;
private final Temporal temporal;
public TemporalDuration(Duration duration) {
this.duration = duration;
this.temporal = duration.addTo(BASE_TEMPORAL);
}
@Override
public boolean isSupported(TemporalField field) {
if(!temporal.isSupported(field)) return false;
long value = temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
return value!=0L;
}
@Override
public long getLong(TemporalField field) {
if(!isSupported(field)) throw new UnsupportedTemporalTypeException(new StringBuilder().append(field.toString()).toString());
return temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
}
public Duration getDuration() {
return duration;
}
@Override
public String toString() {
return dtf.format(this);
}
private static final DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.optionalStart()//second
.optionalStart()//minute
.optionalStart()//hour
.optionalStart()//day
.optionalStart()//month
.optionalStart()//year
.appendValue(ChronoField.YEAR).appendLiteral(" Years ").optionalEnd()
.appendValue(ChronoField.MONTH_OF_YEAR).appendLiteral(" Months ").optionalEnd()
.appendValue(ChronoField.DAY_OF_MONTH).appendLiteral(" Days ").optionalEnd()
.appendValue(ChronoField.HOUR_OF_DAY).appendLiteral(" Hours ").optionalEnd()
.appendValue(ChronoField.MINUTE_OF_HOUR).appendLiteral(" Minutes ").optionalEnd()
.appendValue(ChronoField.SECOND_OF_MINUTE).appendLiteral(" Seconds").optionalEnd()
.toFormatter();
}
Duration.ofSeconds(20)
), maka saya akan mendapatkan UnsupportedTemporalTypeException
). Saya hanya menghapus kode memeriksa apakah perbedaannya == 01
. Saya pikir 01
itu semacam nilai masking yang saya tidak sepenuhnya mengerti, bisakah Anda menjelaskannya?
isSupported
metode ini mengembalikan informasi jika ada bidang yang valid untuk ditampilkan pada string yang dapat dibaca manusia. Pokoknya "masking" sebenarnya bukan topeng. Kode return value!=0l
tidak menunjukkan return value!=01
. Silakan gunakan copy-paste lain kali.
TemporalAccessor
tidak seharusnya disalahgunakan untuk jangka waktu. JSR-310 telah mendesain antarmuka TemporalAmount
untuk tujuan ini.
L
untuk menandakan long
nilai. Sangat mudah untuk salah membaca huruf kecil l
untuk digit 1, seperti yang baru saja ditunjukkan.
Berikut adalah satu lagi contoh cara memformat durasi. Perhatikan bahwa sampel ini menunjukkan durasi positif dan negatif sebagai durasi positif.
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.SECONDS;
import java.time.Duration;
public class DurationSample {
public static void main(String[] args) {
//Let's say duration of 2days 3hours 12minutes and 46seconds
Duration d = Duration.ZERO.plus(2, DAYS).plus(3, HOURS).plus(12, MINUTES).plus(46, SECONDS);
//in case of negative duration
if(d.isNegative()) d = d.negated();
//format DAYS HOURS MINUTES SECONDS
System.out.printf("Total duration is %sdays %shrs %smin %ssec.\n", d.toDays(), d.toHours() % 24, d.toMinutes() % 60, d.getSeconds() % 60);
//or format HOURS MINUTES SECONDS
System.out.printf("Or total duration is %shrs %smin %sec.\n", d.toHours(), d.toMinutes() % 60, d.getSeconds() % 60);
//or format MINUTES SECONDS
System.out.printf("Or total duration is %smin %ssec.\n", d.toMinutes(), d.getSeconds() % 60);
//or format SECONDS only
System.out.printf("Or total duration is %ssec.\n", d.getSeconds());
}
}
Jawaban ini hanya menggunakan Duration
metode dan berfungsi dengan Java 8:
public static String format(Duration d) {
long days = d.toDays();
d = d.minusDays(days);
long hours = d.toHours();
d = d.minusHours(hours);
long minutes = d.toMinutes();
d = d.minusMinutes(minutes);
long seconds = d.getSeconds() ;
return
(days == 0?"":days+" jours,")+
(hours == 0?"":hours+" heures,")+
(minutes == 0?"":minutes+" minutes,")+
(seconds == 0?"":seconds+" secondes,");
}
Bagaimana dengan fungsi berikut, yang mengembalikan + H: MM: SS atau + H: MM: SS.sss
public static String formatInterval(final long interval, boolean millisecs )
{
final long hr = TimeUnit.MILLISECONDS.toHours(interval);
final long min = TimeUnit.MILLISECONDS.toMinutes(interval) %60;
final long sec = TimeUnit.MILLISECONDS.toSeconds(interval) %60;
final long ms = TimeUnit.MILLISECONDS.toMillis(interval) %1000;
if( millisecs ) {
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
} else {
return String.format("%02d:%02d:%02d", hr, min, sec );
}
}
Ada pendekatan yang cukup sederhana dan elegan (IMO), setidaknya untuk jangka waktu kurang dari 24 jam:
DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))
Pemformat memerlukan objek temporal untuk diformat, sehingga Anda dapat membuatnya dengan menambahkan durasi ke LocalTime 00:00 (yaitu tengah malam). Ini akan memberi Anda LocalTime yang menunjukkan durasi dari tengah malam hingga waktu itu, yang kemudian mudah diformat dalam notasi HH: mm: ss standar. Ini memiliki keuntungan karena tidak perlu perpustakaan eksternal, dan menggunakan perpustakaan java.time untuk melakukan perhitungan, daripada secara manual menghitung jam, menit dan detik.
Ini adalah opsi yang berfungsi.
public static String showDuration(LocalTime otherTime){
DateTimeFormatter df = DateTimeFormatter.ISO_LOCAL_TIME;
LocalTime now = LocalTime.now();
System.out.println("now: " + now);
System.out.println("otherTime: " + otherTime);
System.out.println("otherTime: " + otherTime.format(df));
Duration span = Duration.between(otherTime, now);
LocalTime fTime = LocalTime.ofNanoOfDay(span.toNanos());
String output = fTime.format(df);
System.out.println(output);
return output;
}
Panggil metode dengan
System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));
Menghasilkan sesuatu seperti:
otherTime: 09:30
otherTime: 09:30:00
11:31:27.463
11:31:27.463
String duration(Temporal from, Temporal to) {
final StringBuilder builder = new StringBuilder();
for (ChronoUnit unit : new ChronoUnit[]{YEARS, MONTHS, WEEKS, DAYS, HOURS, MINUTES, SECONDS}) {
long amount = unit.between(from, to);
if (amount == 0) {
continue;
}
builder.append(' ')
.append(amount)
.append(' ')
.append(unit.name().toLowerCase());
from = from.plus(amount, unit);
}
return builder.toString().trim();
}
Perpustakaan saya Time4J menawarkan solusi berbasis pola (mirip dengan Apache DurationFormatUtils
, tetapi lebih fleksibel):
Duration<ClockUnit> duration =
Duration.of(-573421, ClockUnit.SECONDS) // input in seconds only
.with(Duration.STD_CLOCK_PERIOD); // performs normalization to h:mm:ss-structure
String fs = Duration.formatter(ClockUnit.class, "+##h:mm:ss").format(duration);
System.out.println(fs); // output => -159:17:01
Kode ini menunjukkan kemampuan untuk menangani overflow jam dan menangani tanda tangan, lihat juga API formatter berdasarkan durasi .
Dalam scala (saya melihat beberapa upaya lain, dan tidak terkesan):
def formatDuration(duration: Duration): String = {
import duration._ // get access to all the members ;)
f"$toDaysPart $toHoursPart%02d:$toMinutesPart%02d:$toSecondsPart%02d:$toMillisPart%03d"
}
Terlihat mengerikan ya? Nah itu sebabnya kami menggunakan IDE untuk menulis hal ini sehingga metode ini memanggil ($toHoursPart
dll) berbeda warna.
The f"..."
adalah printf
/ String.format
interpolator gaya tali (yang adalah apa yang memungkinkan $
kode injeksi bekerja) Mengingat output 1 14:06:32.583
, yang f
tali interpolasi akan setara denganString.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)
menggunakan fungsi ini
private static String strDuration(long duration) {
int ms, s, m, h, d;
double dec;
double time = duration * 1.0;
time = (time / 1000.0);
dec = time % 1;
time = time - dec;
ms = (int)(dec * 1000);
time = (time / 60.0);
dec = time % 1;
time = time - dec;
s = (int)(dec * 60);
time = (time / 60.0);
dec = time % 1;
time = time - dec;
m = (int)(dec * 60);
time = (time / 24.0);
dec = time % 1;
time = time - dec;
h = (int)(dec * 24);
d = (int)time;
return (String.format("%d d - %02d:%02d:%02d.%03d", d, h, m, s, ms));
}
Di Scala, membangun solusi YourBestBet tetapi disederhanakan:
def prettyDuration(seconds: Long): List[String] = seconds match {
case t if t < 60 => List(s"${t} seconds")
case t if t < 3600 => s"${t / 60} minutes" :: prettyDuration(t % 60)
case t if t < 3600*24 => s"${t / 3600} hours" :: prettyDuration(t % 3600)
case t => s"${t / (3600*24)} days" :: prettyDuration(t % (3600*24))
}
val dur = prettyDuration(12345).mkString(", ") // => 3 hours, 25 minutes, 45 seconds
dalam scala, tidak perlu perpustakaan:
def prettyDuration(str:List[String],seconds:Long):List[String]={
seconds match {
case t if t < 60 => str:::List(s"${t} seconds")
case t if (t >= 60 && t< 3600 ) => List(s"${t / 60} minutes"):::prettyDuration(str, t%60)
case t if (t >= 3600 && t< 3600*24 ) => List(s"${t / 3600} hours"):::prettyDuration(str, t%3600)
case t if (t>= 3600*24 ) => List(s"${t / (3600*24)} days"):::prettyDuration(str, t%(3600*24))
}
}
val dur = prettyDuration(List.empty[String], 12345).mkString("")
Saya tidak melihat yang ini jadi saya pikir saya akan menambahkannya:
Date started=new Date();
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
task
long duration=new Date().getTime()-started.getTime();
System.out.println(format.format(new Date(duration));
Ini hanya bekerja selama 24 jam tapi itu yang biasanya saya inginkan untuk durasi.