hora - ¿Cómo formatear una duración en java?(por ejemplo, formato H: MM: SS)
simpledateformat java example (13)
Me gustaría formatear una duración en segundos con un patrón como H: MM: SS. Las utilidades actuales en java están diseñadas para formatear un tiempo pero no una duración.
¿Qué hay de la siguiente función, que devuelve ya sea + H: MM: SS o + 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 );
}
}
Aquí hay una muestra más de cómo formatear la duración. Tenga en cuenta que esta muestra muestra tanto la duración positiva como la negativa como duración positiva.
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());
}
}
Esta es una opción de trabajo.
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;
}
Llamar al método con
System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));
Produce algo como:
otherTime: 09:30
otherTime: 09:30:00
11:31:27.463
11:31:27.463
Esta va a ser una de las nuevas características en java 7
Esto podría ser un poco raro, pero es una buena solución si uno se empeña en lograr esto usando java.time
Java 8:
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();
}
Esto será más fácil con Java 9. Aún no se puede formatear la duración (lo que sé), pero se agregan los métodos para obtener las horas, los minutos y los segundos, lo que hace que la tarea sea más sencilla:
Duration diff = // ...;
String hms = String.format("%d:%02d:%02d",
diff.toHoursPart(),
diff.toMinutesPart(),
diff.toSecondsPart());
Mi biblioteca Time4J ofrece una solución basada en patrones (similar a Apache DurationFormatUtils
, pero más flexible):
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
Este código demuestra las capacidades para manejar el desbordamiento horario y el manejo de letreros, consulte también la API del formateador de duración basada en el patrón .
Si no desea arrastrar bibliotecas, es bastante sencillo hacerlo usted mismo usando un formateador, o un atajo relacionado, por ejemplo. número entero dado de segundos s:
String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
Utilizo DurationFormatUtils Apache common de esta manera:
DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true));
en scala, no se necesita biblioteca:
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("")
Si está utilizando una versión de Java anterior a 8 ... puede usar Joda Time y PeriodFormatter
. Si realmente tiene una duración (es decir, una cantidad de tiempo transcurrida, sin referencia a un sistema de calendario), entonces probablemente debería usar Duration
en su mayor parte; luego puede llamar a toPeriod
(especificando el PeriodType
que desea reflejar ya sea 25 horas se convierte en 1 día y 1 hora o no, etc.) para obtener un Period
que puede formatear.
Si está utilizando Java 8 o posterior: normalmente sugeriría usar java.time.Duration
para representar la duración. A continuación, puede llamar a getSeconds()
o similar para obtener un entero para el formato de cadena estándar según la respuesta de Bobince si lo necesita, aunque debe tener cuidado con la situación donde la duración es negativa, ya que probablemente desee un único signo negativo la cadena de salida. Entonces algo así como:
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;
}
Formatear de esta manera es razonablemente simple, aunque sea molestamente manual. Para el análisis, se convierte en una cuestión más difícil en general ... Todavía puede utilizar Joda Time, incluso con Java 8 si lo desea, por supuesto.
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();
}
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())));