Javaで期間をフォーマットする方法は?(例:フォーマットH:MM:SS)


164

H:MM:SSのようなパターンを使用して、秒単位で期間をフォーマットしたいと思います。現在のJavaのユーティリティは、時間ではなく時間をフォーマットするように設計されています。

回答:


84

8より前のバージョンのJavaを使用している場合は、Joda Timeおよびを使用できますPeriodFormatter。あなたが本当に期間(つまり、カレンダーシステムを参照しない経過時間)を持っているなら、あなたはおそらくDuration大部分を使用しているはずです-あなたは次に呼び出すことができますtoPeriodPeriodType25時間になるかどうかを反映したいものを指定します) 1日と1時間かどうかなど)でPeriodフォーマットできるものを取得します。

Java 8以降を使用している場合:通常、を使用java.time.Durationして期間を表すことをお勧めします。次に、getSeconds()必要に応じて、ボビンスの回答に従って標準文字列フォーマットの整数を取得するなどを呼び出すことができます。ただし、出力文字列に単一の負符号が必要になる可能性があるため、期間が負である状況には注意する必要があります。 。したがって、次のようなもの:

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とジョダ時間を使用することができます。


Java 8を使用する場合でも、Joda Timeライブラリを使用することをお勧めしますか?
TimBüthe2014

1
@TimBüthe:いいえ、その場合はjava.timeを使い始めます。(PeriodFormatterに相当するものはすぐには見つかりませんが...)
Jon Skeet

1
PeriodFormatterは含まれていません。Java 8 Date Time APIとJoda Timeの違いの1つです。
TimBüthe2014

1
@RexKerr:ええと、もちろん、もし望むなら、「Joda Timeを使う」というのはまだあります。再度編集します。(振り返ってみると、とにかく、その音から、Durationを推奨しているはずです。大幅な編集が必要です...)
Jon Skeet

4
@MarkJeronimus Durationsメソッドを使用する方が簡単です。duration.toHours()duration.toMinutesPart()およびduration.toSecondsPart()Java 9以降で使用できますduration.abs()。絶対値を取得するには、を使用できます。
recke96

195

ライブラリをドラッグしたくない場合は、フォーマッタや関連するショートカットを使用して簡単に行えます。秒数を指定した整数s:

  String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));

4
整数である必要はありません。2つの日付がある場合は、date1.getTime()-date2.getTime()を、長いプリミティブを使用し、引き続き機能する上記の式にプラグインします。
Josh、

時差が24時間より長い場合はどうなりますか?
ラジッシュ2011

2
@Rajish:その場合、OPに何が欲しいか尋ねる必要があります!もちろんs/86400, (s%86400)/3600...、必要に応じて数日間に分割することもできます...
bobince

私の解決策s > 8640:(1日)0 "\u221E"-無限大
QED

時差が24時間を超えている場合でも、期間は時間、分、秒で適切にフォーマットされます。私の使用例では、これは予想どおりです。
Audrius Meskauskas

122

私はApache commonのDurationFormatUtilsを次のように使用しています:

DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);

13
可能な最も簡単な方法(Apache Commonsスタイル)。formatDurationHMSメソッドもあり、ほとんどの場合はおそらく使用します。
マルコ

パーフェクト!アポストロフィ内に他のテキストを追加することもできます:DurationFormatUtils.formatDuration(durationInMillis、 "m 'minutes'、s 'seconds'")
mihca

29

これはJava 9以降で簡単です。Aは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


26
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())));

14
ハァッ!この方法を使用する場合は、タイムゾーンの正規化で壁にぶつかるだけです。関数sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));を使用する前に追加する必要がありformatます。
ラジッシュ2011

7

これは一種のハックかもしれませんが、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();

}

私はこれを試みたが、私は「HH:MM:SS」の形式を呼び出した場合に気づい私はdidntの形式に任意の時間または数分を持っている(例えばDuration.ofSeconds(20))、その後、私は取得したいですUnsupportedTemporalTypeException)。違いがあるかどうかを確認するコードを単に削除しました== 01。私01は完全には理解できないある種のマスキング値であると考えました、それを説明できますか?
Groostav 2015

これは実際には非常にうまくいきました。私の場合、ミリ秒も追加しました... isSupportedメソッドに関しては、人間が読める文字列に表示する有効なフィールドがある場合、情報を返します。とにかく、「マスキング」は実際にはマスクではありません。コードはreturn value!=0lnotを示していreturn value!=01ます。次回はコピー&ペーストをご利用ください。
MrJames

1
インターフェースTemporalAccessorは、使用期間中は誤用されるべきではありません。JSR-310はTemporalAmountこの目的のためにインターフェースを設計しました。
Meno Hochschild 2017年

1
Lを表す場合は常に大文字を使用することをお勧めしますlongl先ほど示したように、小文字を数字1 と読み間違えるのはとても簡単です。
Ole VV

6

デュレーションをフォーマットする方法のもう1つのサンプルを次に示します。このサンプルは、正の期間として正と負の両方の期間を示していることに注意してください。

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());
    }
}

5

この回答は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+" jours,")+ 
            (hours == 0?"":hours+" heures,")+ 
            (minutes ==  0?"":minutes+" minutes,")+ 
            (seconds == 0?"":seconds+" secondes,");
}

4

+ H:MM:SSまたは+ 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 );
    }
}

4

少なくとも24時間未満の期間については、かなりシンプルで(IMO)エレガントなアプローチがあります。

DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))

フォーマッターはフォーマットするために一時オブジェクトを必要とするので、LocalTimeに00:00(つまり、真夜中)に期間を追加することにより、一時オブジェクトを作成できます。これにより、午前0時からその時刻までの期間を表すLocalTimeが得られ、標準のHH:mm:ss表記で簡単にフォーマットできます。これには、外部ライブラリを必要としないという利点があり、時間、分、秒を手動で計算するのではなく、java.timeライブラリを使用して計算を行います。


3

これは有効なオプションです。

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;
}

でメソッドを呼び出す

System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));

次のようなものを生成します:

otherTime: 09:30
otherTime: 09:30:00
11:31:27.463
11:31:27.463

2
これは、23:59:59.999を超える継続時間では失敗します。
ミシェルユング

2
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();
}

0

私のライブラリTime4Jは、パターンベースのソリューションを提供しています(に似てApache DurationFormatUtilsいますが、より柔軟です)。

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

このコードは、時間オーバーフローと符号処理を処理する機能を示しています。patternに基づく duration-formatterのAPIも参照してください。


0

スカラ(私はいくつかの他の試みを見た、そして感銘を受けなかった):

def formatDuration(duration: Duration): String = {
  import duration._ // get access to all the members ;)
  f"$toDaysPart $toHoursPart%02d:$toMinutesPart%02d:$toSecondsPart%02d:$toMillisPart%03d"
}

恐ろしいですね さて、これをIDEを使用してこのように記述し、メソッド呼び出し($toHoursPartなど)を別の色にしています。

f"..."あるprintf/のString.format(可能にするものである形式の文字列補間$の出力を考えると仕事へのコードインジェクション)を1 14:06:32.583f補間された文字列がに相当しますString.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)


0

この関数を使用して

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));
}

行くgithub.com/ipserc/durationこの機能のパッケージ版を得るために
ipserc

-1

Scalaでは、YourBestBetのソリューションに基づいて構築しますが、以下を簡素化します。

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

-2

スカラでは、ライブラリは必要ありません:

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("")

3
これはScalaの優れた広告ではありませんか?ライブラリは必要ありませんが、同じくらい多くのコード...?
アダム

私は、再帰的なアプローチのように、それは多くのことを簡素化することができます。stackoverflow.com/a/52992235/3594403
dpoetzsch

-2

私はこれを見なかったので、追加すると思いました:

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));

それは24時間だけ機能しますが、それは私が通常持続したいものです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.