Câu trả lời:
Nếu bạn đang sử dụng phiên bản Java trước 8 ... bạn có thể sử dụng Joda Time và PeriodFormatter
. Nếu bạn thực sự có một khoảng thời gian (tức là một khoảng thời gian đã trôi qua, không có tham chiếu đến hệ thống lịch) thì có lẽ bạn nên sử dụng Duration
phần lớn - sau đó bạn có thể gọi toPeriod
(chỉ định bất cứ điều gì PeriodType
bạn muốn phản ánh cho dù 25 giờ có trở thành 1 ngày và 1 giờ hoặc không, v.v.) để có được Period
định dạng mà bạn có thể định dạng.
Nếu bạn đang sử dụng Java 8 trở lên: Tôi thường đề xuất sử dụng java.time.Duration
để thể hiện thời lượng. Sau đó, bạn có thể gọi getSeconds()
hoặc muốn lấy số nguyên để định dạng chuỗi tiêu chuẩn theo câu trả lời của bobince nếu bạn cần - mặc dù bạn nên cẩn thận với tình huống trong đó thời lượng là âm, vì bạn có thể muốn có một dấu âm duy nhất trong chuỗi đầu ra . Vì vậy, một cái gì đó như:
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;
}
Định dạng theo cách này là hợp lý đơn giản, nếu thủ công gây khó chịu. Để phân tích cú pháp , nói chung trở thành một vấn đề khó hơn ... Bạn vẫn có thể sử dụng Joda Time ngay cả với Java 8 nếu bạn muốn, tất nhiên.
Duration
phương pháp s: duration.toHours()
, duration.toMinutesPart()
và duration.toSecondsPart()
trong đó có sẵn từ Java 9. Và để có được giá trị một tuyệt đối có thể sử dụng duration.abs()
.
Nếu bạn không muốn kéo vào thư viện, thì đủ đơn giản để bạn tự sử dụng Trình định dạng hoặc phím tắt có liên quan, vd. số nguyên đã cho của giây s:
String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
s/86400, (s%86400)/3600...
nhiều ngày nếu cần thiết ...
s > 8640
0 (một ngày): "\u221E"
- vô cùng
Tôi sử dụng Apache chung DurationFormatUtils như vậy:
DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
Điều này dễ dàng hơn kể từ Java 9. Một Duration
vẫn không thể định dạng được, nhưng các phương thức để lấy giờ, phút và giây được thêm vào, điều này làm cho nhiệm vụ có phần đơn giản hơn:
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);
Đầu ra từ đoạn trích này là:
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"));
trước khi sử dụng format
chức năng.
Đây có thể là một loại hacky, nhưng nó là một giải pháp tốt nếu người ta cố gắng hoàn thành việc này bằng cách sử dụng Java 8 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)
), sau đó tôi muốn có được một UnsupportedTemporalTypeException
). Tôi chỉ đơn giản là loại bỏ mã kiểm tra nếu sự khác biệt là == 01
. Tôi hình dung 01
là một loại giá trị che giấu mà tôi không hiểu hết, bạn có thể giải thích nó không?
isSupported
phương thức nó trả lại thông tin nếu có trường hợp lệ để hiển thị trên chuỗi có thể đọc được của con người. Dù sao thì "mặt nạ" thực sự không phải là mặt nạ. Các mã cho thấy return value!=0l
không return value!=01
. Vui lòng sử dụng bản sao-dán lần sau.
TemporalAccessor
không được sử dụng sai cho thời lượng. JSR-310 đã thiết kế giao diện TemporalAmount
cho mục đích này.
L
để biểu thị một long
giá trị. Thật dễ dàng để đọc sai chữ thường l
cho chữ số 1, như vừa trình bày.
Đây là một mẫu nữa làm thế nào để định dạng thời lượng. Lưu ý rằng mẫu này cho thấy cả thời gian dương và âm là thời lượng dương.
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());
}
}
Câu trả lời này chỉ sử dụng Duration
các phương thức và hoạt động với 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,");
}
Làm thế nào về chức năng sau, trả về + H: MM: SS hoặc + 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 );
}
}
Có một cách tiếp cận khá đơn giản và (IMO), ít nhất là trong khoảng thời gian dưới 24 giờ:
DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))
Trình định dạng cần một đối tượng tạm thời để định dạng, vì vậy bạn có thể tạo một đối tượng bằng cách thêm thời lượng vào LocalTime là 00:00 (tức là nửa đêm). Điều này sẽ cung cấp cho bạn một LocalTime biểu thị thời lượng từ nửa đêm đến thời điểm đó, sau đó dễ dàng định dạng theo ký hiệu HH: mm: ss tiêu chuẩn. Điều này có lợi thế là không cần thư viện bên ngoài và sử dụng thư viện java.time để thực hiện phép tính, thay vì tính toán thủ công giờ, phút và giây.
Đây là một lựa chọn làm việc.
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;
}
Gọi phương thức với
System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));
Sản xuất một cái gì đó như:
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();
}
Thư viện của tôi Time4J cung cấp một giải pháp dựa trên mẫu (tương tự Apache DurationFormatUtils
, nhưng linh hoạt hơn):
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
Mã này thể hiện các khả năng xử lý tràn giờ và xử lý dấu hiệu, xem thêm API của trình định dạng thời lượng dựa trên mẫu .
Trong scala (tôi đã thấy một số nỗ lực khác và không ấn tượng):
def formatDuration(duration: Duration): String = {
import duration._ // get access to all the members ;)
f"$toDaysPart $toHoursPart%02d:$toMinutesPart%02d:$toSecondsPart%02d:$toMillisPart%03d"
}
Có vẻ kinh khủng đúng không? Đó là lý do tại sao chúng tôi sử dụng IDE để viết nội dung này sao cho các cuộc gọi phương thức ( $toHoursPart
vv) có màu khác.
Bộ nội suy chuỗi f"..."
là printf
/ String.format
kiểu (là thứ cho phép phép $
tiêm mã hoạt động) Với đầu ra là 1 14:06:32.583
, f
chuỗi nội suy sẽ tương đương vớiString.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)
sử dụng chức năng này
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));
}
Trong Scala, xây dựng giải pháp của YourBestBet nhưng được đơn giản hóa:
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
trong scala, không cần thư viện:
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("")
Tôi đã không nhìn thấy cái này vì vậy tôi nghĩ tôi muốn thêm nó:
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));
Nó chỉ hoạt động trong 24 giờ nhưng đó là những gì tôi thường muốn trong thời gian.