Réponses:
Si vous utilisez une version de Java antérieure à 8 ... vous pouvez utiliser Joda Time et PeriodFormatter
. Si vous avez vraiment une durée (c'est-à-dire une durée écoulée, sans référence à un système de calendrier), vous devriez probablement l'utiliser Duration
pour la plupart - vous pouvez alors appeler toPeriod
(en spécifiant ce que PeriodType
vous voulez pour indiquer si 25 heures deviennent 1 jour et 1 heure ou pas, etc.) pour obtenir un Period
format que vous pouvez formater.
Si vous utilisez Java 8 ou version ultérieure: je suggère normalement d'utiliser java.time.Duration
pour représenter la durée. Vous pouvez ensuite appeler getSeconds()
ou similaire pour obtenir un entier pour le formatage de chaîne standard selon la réponse de bobince si vous en avez besoin - bien que vous devriez faire attention à la situation où la durée est négative, car vous voulez probablement un seul signe négatif dans la chaîne de sortie . Donc quelque chose comme:
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;
}
Le formatage de cette manière est raisonnablement simple, bien que manuel ennuyeux. Pour l' analyse cela devient une question plus difficile en général ... Vous pouvez toujours utiliser Joda Time même avec Java 8 si vous le souhaitez, bien sûr.
Duration
méthodes de s: duration.toHours()
, duration.toMinutesPart()
et duration.toSecondsPart()
qui sont disponibles depuis Java 9. Et pour obtenir la valeur absolue peut utiliser duration.abs()
.
Si vous ne voulez pas faire glisser dans les bibliothèques, c'est assez simple de le faire vous-même en utilisant un formateur ou un raccourci associé, par exemple. donné nombre entier de secondes s:
String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
s/86400, (s%86400)/3600...
jours si nécessaire ...
s > 8640
0 (un jour): "\u221E"
- infini
J'utilise DurationFormatUtils d' Apache commun comme ceci:
DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
C'est plus facile depuis Java 9. A Duration
n'est toujours pas formatable, mais des méthodes pour obtenir les heures, minutes et secondes sont ajoutées, ce qui rend la tâche un peu plus simple:
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);
Le résultat de cet extrait de code est:
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"));
avant d'utiliser la format
fonction.
DateFormat.getDateInstance()
au lieu de classes concrètes.
Cela peut être un peu piraté, mais c'est une bonne solution si l'on veut accomplir cela en utilisant 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)
), alors j'obtiendrais un UnsupportedTemporalTypeException
). J'ai simplement supprimé le code vérifiant si la différence est == 01
. J'ai pensé qu'il y 01
avait une sorte de valeur de masquage que je ne comprends pas complètement, pouvez-vous l'expliquer?
isSupported
méthode, il renvoie les informations s'il existe un champ valide à afficher sur la chaîne lisible par l'homme. Quoi qu'il en soit, le "masquage" n'est en fait pas un masque. Le code return value!=0l
ne montre pas return value!=01
. Veuillez utiliser le copier-coller la prochaine fois.
TemporalAccessor
n'est pas censée être mal utilisée pendant des durées. JSR-310 a conçu l'interface TemporalAmount
à cet effet.
L
pour signifier une long
valeur. Il est si facile de mal interpréter les minuscules l
pour le chiffre 1, comme je viens de le démontrer.
Voici un autre exemple de formatage de la durée. Notez que cet échantillon montre à la fois la durée positive et la durée négative comme une durée positive.
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());
}
}
Cette réponse utilise uniquement des Duration
méthodes et fonctionne avec 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,");
}
Ceci est une option de travail.
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;
}
Appelez la méthode avec
System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));
Produit quelque chose comme:
otherTime: 09:30
otherTime: 09:30:00
11:31:27.463
11:31:27.463
Que diriez-vous de la fonction suivante, qui renvoie soit + H: MM: SS ou + 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 );
}
}
Il existe une approche assez simple et élégante (IMO), au moins pour des durées inférieures à 24 heures:
DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))
Les formateurs ont besoin d'un objet temporel pour formater, vous pouvez donc en créer un en ajoutant la durée à un LocalTime de 00:00 (c'est-à-dire minuit). Cela vous donnera un LocalTime représentant la durée de minuit à cette heure, qui est alors facile à formater en notation standard HH: mm: ss. Cela a l'avantage de ne pas avoir besoin d'une bibliothèque externe et utilise la bibliothèque java.time pour faire le calcul, plutôt que de calculer manuellement les heures, les minutes et les secondes.
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();
}
en utilisant cette fonction
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));
}
Ma bibliothèque Time4J propose une solution basée sur des modèles (similaire Apache DurationFormatUtils
, mais plus 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
Ce code montre les capacités de gérer le dépassement d'heures et la gestion des signes, voir aussi l'API de duration-formatter basé sur un modèle .
Dans scala (j'ai vu d'autres tentatives et je n'ai pas été impressionné):
def formatDuration(duration: Duration): String = {
import duration._ // get access to all the members ;)
f"$toDaysPart $toHoursPart%02d:$toMinutesPart%02d:$toSecondsPart%02d:$toMillisPart%03d"
}
Ça a l'air horrible, oui? Eh bien, c'est pourquoi nous utilisons des IDE pour écrire ce truc de sorte que les appels de méthode ( $toHoursPart
etc.) soient d'une couleur différente.
L' interpolateur de chaîne f"..."
est un printf
/ String.format
style (ce qui permet à l' $
injection de code de fonctionner) Étant donné une sortie de 1 14:06:32.583
, la f
chaîne interpolée serait équivalente àString.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)
Dans Scala, s'appuyer sur la solution de YourBestBet mais simplifié:
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
dans scala, aucune bibliothèque nécessaire:
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("")
Je n'ai pas vu celui-ci alors j'ai pensé l'ajouter:
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));
Cela ne fonctionne que pendant 24 heures, mais c'est ce que je veux généralement pour la durée.