如何在java中格式化持续时间?(例如格式 H:MM:SS)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/266825/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:14:09  来源:igfitidea点击:

How to format a duration in java? (e.g format H:MM:SS)

javadate-formattingduration

提问by

I'd like to format a duration in seconds using a pattern like H:MM:SS. The current utilities in java are designed to format a time but not a duration.

我想使用像 H:MM:SS 这样的模式以秒为单位格式化持续时间。java中的当前实用程序旨在格式化时间而不是持续时间。

采纳答案by Jon Skeet

If you're using a version of Java prior to 8... you can use Joda Timeand PeriodFormatter. If you've really got a duration (i.e. an elapsed amount of time, with no reference to a calendar system) then you should probably be using Durationfor the most part - you can then call toPeriod(specifying whatever PeriodTypeyou want to reflect whether 25 hours becomes 1 day and 1 hour or not, etc) to get a Periodwhich you can format.

如果您使用的是 8 之前的 Java 版本...您可以使用Joda TimePeriodFormatter. 如果你真的有一个持续时间(即经过的时间量,没有参考日历系统)那么你可能应该使用Duration大部分 - 然后你可以打电话toPeriod(指定PeriodType你想要反映的任何内容,以反映 25 小时是否变成1 天 1 小时与否等)以获得Period您可以格式化的文件。

If you're using Java 8 or later: I'd normally suggest using java.time.Durationto represent the duration. You can then call getSeconds()or the like to obtain an integer for standard string formatting as per bobince's answer if you need to - although you should be careful of the situation where the duration is negative, as you probably want a singlenegative sign in the output string. So something like:

如果您使用的是 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;
}

Formatting this way is reasonablysimple, if annoyingly manual. For parsingit becomes a harder matter in general... You could still use Joda Time even with Java 8 if you want to, of course.

以这种方式格式化相当简单,如果手动操作很烦人。对于解析它变成一般较硬的事......如果你愿意,你当然可以仍然使用约达时间甚至与Java 8。

回答by bobince

If you don't want to drag in libraries, it's simple enough to do yourself using a Formatter, or related shortcut eg. given integer number of seconds s:

如果您不想在库中拖动,那么使用格式化程序或相关快捷方式(例如)很简单。给定整数秒数:

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

回答by Mihai Vasilache

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

回答by Gili Nachum

I use Apache common's DurationFormatUtilslike so:

我像这样使用 Apache common 的DurationFormatUtils

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

回答by sbclint

This is a working option.

这是一个工作选项。

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

Call the method with

调用方法

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

Produces something like:

产生类似的东西:

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

回答by patrick

This might be kind of hacky, but it is a good solution if one is bent on accomplishing this using Java 8's java.time:

这可能有点 hacky,但如果人们一心想使用 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();

}

回答by Pavel_H

Here is one more sample how to format duration. Note that this sample shows both positive and negative duration as positive duration.

这是如何格式化持续时间的另一个示例。请注意,此示例将正持续时间和负持续时间都显示为正持续时间。

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

回答by Meno Hochschild

My library Time4Joffers a pattern-based solution (similar to Apache DurationFormatUtils, but more flexible):

我的库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

This code demonstrates the capabilities to handle hour overflow and sign handling, see also the API of duration-formatter based on pattern.

此代码演示了处理小时溢出和符号处理的功能,另请参阅基于模式的持续时间格式化程序的 API 。

回答by Bax

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

回答by Ole V.V.

This is easier since Java 9. A Durationstill isn't formattable, but methods for getting the hours, minutes and seconds are added, which makes the task somewhat more straightforward:

从 Java 9 开始,这更容易了。 ADuration仍然不是可格式化的,但添加了获取小时、分钟和秒的方法,这使任务更加简单:

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

The output from this snippet is:

此代码段的输出是:

24:19:21

24:19:21