我想使用“H:MM:SS”这样的格式来格式化以秒为单位的时间段。目前Java中的实用工具是设计用来格式化时间而不是持续时间。
我想使用“H:MM:SS”这样的格式来格式化以秒为单位的时间段。目前Java中的实用工具是设计用来格式化时间而不是持续时间。
如果您不想使用库,可以使用格式化程序或相关快捷方式自行完成。例如,给定秒数为s:
String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
我使用Apache common的DurationFormatUtils,用法如下:
DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
PeriodFormatter
。如果您真的有一个持续时间(即经过的时间,没有参考日历系统),那么大多数情况下应该使用Duration
- 然后您可以调用toPeriod
(指定任何您想要反映25小时变成1天1小时等的PeriodType
)以获取您可以格式化的Period
。java.time.Duration
来表示持续时间。然后,如果需要,您可以调用getSeconds()
之类的函数来获得整数以进行标准字符串格式化,就像bobince的答案一样 - 尽管您应该注意持续时间为负的情况,因为您可能想要在输出字符串中使用一个负号。所以类似这样: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;
}
如果只是格式化,这种方式相对简单,但是手动操作可能有些烦人。而对于解析来说,一般情况下会更加困难……当然,如果你想要的话,即使在使用Java 8的情况下仍然可以使用Joda Time。
Duration
类的方法:duration.toHours()
,duration.toMinutesPart()
和duration.toSecondsPart()
。这些方法从Java 9版本开始可用。要获取绝对值,可以使用duration.abs()
。 - recke96自Java 9开始,这变得更容易了。虽然Duration
仍然不能格式化,但添加了获取小时、分钟和秒的方法,使得该任务变得更加简单:
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);
此片段的输出结果为:
24:19:21
"${diff.toHours()}:${diff.toMinutesPart()}:${diff.toSecondsPart()}"
- undefinedlong 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())));
format
函数之前,您需要添加sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));
。 - RajishDateFormat.getDateInstance()
而不是具体的类。 - Abhijit Sarkar00:00:00.000
。此外,负一秒被格式化为 23:59:59.000
。 - V.S.对于小于24小时的时间段,有一种相当简单且(在我看来)优雅的方法:
DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))
格式化程序需要一个时间对象才能进行格式化,因此您可以通过将持续时间添加到00:00(即午夜)的本地时间上来创建一个时间对象。这将为您提供从午夜到该时间的本地时间,很容易以标准的HH:mm:ss格式进行格式化。这种方法的优点是不需要外部库,并使用java.time库进行计算,而不是手动计算小时、分钟和秒。
这个答案只使用Duration
方法,并且适用于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+" days,")+
(hours == 0?"":hours+" hours,")+
(minutes == 0?"":minutes+" minutes,")+
(seconds == 0?"":seconds+" seconds,");
}
这可能有点粗糙,但如果想使用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)
),调用“hh:mm:ss”的格式,则会出现“UnsupportedTemporalTypeException”。我只是删除了检查差异是否为“== 01”的代码。我想“01”是某种掩码值,我不完全理解,你能解释一下吗? - GroostavisSupported
方法,它返回信息是否有有效字段可显示在人类可读字符串上。无论如何,“掩码”实际上并不是掩码。代码显示 return value!=0l
而不是 return value!=01
。下次请使用复制粘贴。 - MrJamesTemporalAccessor
不应被误用于表示持续时间。JSR-310专门为此设计了接口TemporalAmount
。 - Meno HochschildL
来表示 long
值。很容易将小写的 l
误读为数字 1,就像刚才演示的那样。 - Ole V.V.还有另一种方法可以使其适用于Java8。不过,它仅在持续时间不超过24小时时才有效。
public String formatDuration(Duration duration) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h:mm.SSS");
return LocalTime.ofNanoOfDay(duration.toNanos()).format(formatter);
}
ofNanoOfDay
,toNanos
... 为什么是LocalTime
。在持续时间的上下文中这毫无意义 :-\ 然而它确实可以解决问题。 - t3chb0tDuration
需要转换为 LocalTime
才能使用其 format
方法。至于纳秒,它们用于获取毫秒数,但我们也可以编写类似于 LocalTime.ofSecondOfDay(duration.getSeconds()).format(formatter)
的代码。 - stanley
s / 86400,(s%86400)/ 3600 ...
以获取天数... - bobinces > 86400
(一天)的解决方案是"\u221E"
- 无穷大。 - QED