如何在Java中格式化时间?(例如,格式为H:MM:SS)

229

我想使用“H:MM:SS”这样的格式来格式化以秒为单位的时间段。目前Java中的实用工具是设计用来格式化时间而不是持续时间。

22个回答

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

6
以下是一个函数示例,它返回以下两种格式之一: +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 );
    }
}

6
你可以使用模拟ISO-8601标准java.time.Duration进行计算。该类别是作为JSR-310实现中Java-8引入的。在Java-9中,还引入了更多方便的方法。
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;

public class Main {
    public static void main(String[] args) {
        LocalDateTime startDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 15, 20, 25);
        LocalDateTime endDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 18, 24, 30);

        Duration duration = Duration.between(startDateTime, endDateTime);
        // Default format
        System.out.println(duration);

        // Custom format
        // ####################################Java-8####################################
        String formattedElapsedTime = String.format("%02d:%02d:%02d", duration.toHours() % 24,
                duration.toMinutes() % 60, duration.toSeconds() % 60);
        System.out.println(formattedElapsedTime);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedElapsedTime = String.format("%02d:%02d:%02d", duration.toHoursPart(), duration.toMinutesPart(),
                duration.toSecondsPart());
        System.out.println(formattedElapsedTime);
        // ##############################################################################
    }
}

输出:

PT3H4M5S
03:04:05
03:04:05

了解现代时间日期API,请参考Java 新时间日期API教程


4

以下是将 java.time.Duration 转换为易读字符串的 Kotlin 代码:

duration.run {
   "%d:%02d:%02d.%03d".format(toHours(), toMinutesPart(), toSecondsPart(), toMillisPart())
}

Example output: 120:56:03.004


4

这是一个有效的选项。

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

4
超过23小时59分59.999秒的时间长度将导致此操作失败。 - Michel Jung

3
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
在Scala中(我看到了一些其他的尝试,但并不印象深刻):
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.583,则f内插的字符串将等同于String.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)


OP要求在Java中格式化以秒为单位的持续时间的解决方案。 - maxxyme
@maxxyme 确实如此。但是我是通过 Scala 搜索词找到这个问题的。其他 Scala 回答(现在已经被严重踩)非常糟糕。我不会让别人去发现那些回答。 一旦有人使用特定的问答链接到这里(可以复制此文本),那么我就会将其删除。在此之前,即使在错误的位置,它仍然具有实用性。 - Stephen
1
@maxxyme 我同意Stephen的观点。Scala、Kotlin和其他基于JVM的语言的程序员经常会搜索如何在Java中实现某些功能,最终会来到这里。因此,在这种情况下,提供一个Scala答案来补充Java答案是有帮助的。 - Ole V.V.

1

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

这段代码展示了处理小时溢出和符号处理的能力,另外还可以查看基于模式的持续时间格式化API (link1)


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

前往 https://github.com/ipserc/duration 获取此函数的打包版本。 - ipserc
这就是我在寻找的代码,被采纳的答案很好,但缺少了我需要的天数。 - Filnor

0

看着所有这些计算,很有帮助的是大多数单位(小时、分钟等)都有一个 .toFooPart() 便捷方法。

例如:

Duration.ofMinutes(110L).toMinutesPart() == 50

阅读:距离父单位(小时)下一个值经过的分钟数。


请不要回答与问题无关的内容,保持专注于问题本身。 - maxxyme

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接