자바에서 지속 시간을 포맷하는 방법은 무엇입니까? (예 : H : MM : SS 형식)


165

H : MM : SS와 같은 패턴을 사용하여 지속 시간을 초 단위로 포맷하고 싶습니다. Java의 현재 유틸리티는 시간 형식이 아닌 시간 형식을 지정하도록 설계되었습니다.

답변:


84

8 이전의 Java 버전을 사용하는 경우 Joda Time 및을 사용할 수 있습니다 PeriodFormatter. 실제로 지속 시간 (예 : 달력 시스템을 참조하지 않고 경과 된 시간)이 있다면 아마도 Duration대부분 을 사용해야 할 것입니다 -그런 다음 전화를 걸 수 있습니다 toPeriod( PeriodType25 시간이 될지 여부를 반영하려는 모든 것을 지정하십시오) 1 일 1 시간 등) Period형식을 지정할 수 있습니다.

Java 8 이상을 사용하는 경우 일반적으로 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;
}

이런 식으로 포맷 것은 합리적 귀찮게 매뉴얼 경우, 간단한. 위해 분석 은 물론, 원하는 경우가 더 열심히 문제 일반적으로이된다 ... 당신은 여전히 심지어 자바 8 Joda 시간을 사용할 수 있습니다.


Java 8을 사용할 때 Joda Time 라이브러리를 계속 사용 하시겠습니까?
Tim Büthe

1
@ TimBüthe : 아니오, 그 경우 java.time을 사용하기 시작합니다. (나는 PeriodFormatter에 해당하는 것을 즉시 찾을 수는 없지만 ...)
Jon Skeet

1
PeriodFormatter는 포함되어 있지 않습니다. Java 8 Date Time API와 Joda Time의 차이점 중 하나입니다.
Tim Büthe

1
@RexKerr : 물론, 원한다면 여전히 "Joda Time 사용"이 있습니다. 다시 편집합니다. (돌이켜 보면, 어쨌든 듀레이션의 소리에 의해 Duration을 추천 했어야했다. 상당한 편집이 필요하다 ...)
Jon Skeet

4
더 쉬운 방법 @MarkJeronimus은 사용하는 것입니다 Duration의 방법 : duration.toHours(), duration.toMinutesPart()그리고 duration.toSecondsPart()자바 9. 이후 사용할 수있는 그리고 절대 값 하나를 사용할 수 있습니다 얻을 duration.abs().
recke96

195

라이브러리에서 드래그하지 않으려는 경우 Formatter 또는 관련 바로 가기와 같은 직접 작성을 사용하는 것이 간단합니다. 주어진 정수 초 수 s :

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

4
정수일 필요는 없습니다. 두 개의 날짜가있는 경우 date1.getTime ()-date2.getTime ()을 긴 기본 형식을 사용하고 여전히 작동하는 위의 방정식에 연결하십시오.
Josh

시차가 24 시간보다 길면 어떻게 되나요?
Rajish

2
@Rajish :이 경우 OP에 원하는 것을 OP해야합니다. 물론 s/86400, (s%86400)/3600...필요한 경우 며칠 동안 분리 할 수 ​​있습니다 .
bobince

s > 86400에 대한 나의 해결책 (1 일) : "\u221E"-무한대
QED

시간 차이가 24 시간을 초과해도 여전히 시간, 분 및 초 단위로 멋지게 포맷됩니다. 내 유스 케이스의 경우 이것은 예상대로입니다.
Audrius Meskauskas

123

Apache common의 DurationFormatUtils를 다음 과 같이 사용합니다.

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

13
가장 쉬운 방법 (아파치 커먼즈 스타일). 아마도 대부분의 시간을 사용하는 formatDurationHMS 메소드가 있습니다.
Marko

완전한! 아포스트로피 내에 다른 텍스트를 추가 할 수도 있습니다. 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합니다.
Rajish

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

이것은 실제로 매우 잘 작동했습니다. 제 경우에는 밀리 초도 추가했습니다 ... isSupported인간이 읽을 수있는 문자열에 표시 할 유효한 필드가있는 경우 메서드를 반환하여 정보를 반환합니다. 어쨌든 "마스킹"은 실제로 마스크가 아닙니다. 코드가 표시 return value!=0l되지 않습니다 return value!=01. 다음에 복사 붙여 넣기를 사용하십시오.
MrJames

1
인터페이스 TemporalAccessor는 오랫동안 오용되어서는 안됩니다. JSR-310 TemporalAmount은이를 위해 인터페이스 를 설계했습니다 .
Meno Hochschild

1
항상 값 L을 나타내는 데 대문자 를 사용하는 것이 좋습니다 long. l방금 설명한 것처럼 숫자 1의 소문자 를 쉽게 읽을 수 있습니다 .
Ole VV

6

다음은 지속 시간을 형식화하는 방법에 대한 샘플입니다. 이 샘플은 양수 기간과 음수 기간을 양수 기간으로 표시합니다.

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 (자정)에 지속 시간을 추가하여 생성 할 수 있습니다. 자정부터 해당 시간까지의 지속 시간을 나타내는 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보다 큰 시간 동안 실패합니다.
Michel Jung

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

1

이 기능을 사용하여

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

이것은 내가 찾던 코드 였고, 받아 들여진 대답은 훌륭하지만, 필요한 날이 부족합니다.
Filnor

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"..."A는 printf/의 String.format합니다 (수 무엇 스타일의 문자열 보간 $의 출력을 감안할 때 작업에 코드 주입) 1 14:06:32.5831, f보간 된 문자열에 해당 될 것String.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)


-1

스칼라에서 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
스칼라에게 좋은 광고가 아니십니까? 라이브러리는 필요하지 않지만 많은 코드가 필요합니다 ...?
Adam

내가 재귀 접근처럼,하지만 많이 단순화 할 수 있습니다 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.