在Java中打印时间差的最通俗易懂的方式是什么?

16

我熟悉以毫秒为单位打印时间差:

 long time = System.currentTimeMillis();
 //do something that takes some time...
 long completedIn = System.currentTimeMillis() - time;

然而,是否有一种好的方式以指定格式(例如:HH:MM:SS)打印完整时间,无论是使用Apache Commons还是甚至可怕的平台API的Date/Time对象?换句话说,在Java中从毫秒派生时间格式的最短、最简单、最直接的方法是什么?


3
应该是 System.currentTimeMillis() - time; - Péter Török
6个回答

23

Apache Commons提供了DurationFormatUtils类,用于将指定格式应用于时间持续时间。因此,可以使用以下代码实现:

long time = System.currentTimeMillis();
//do something that takes some time...
long completedIn = System.currentTimeMillis() - time;

DurationFormatUtils.formatDuration(completedIn, "HH:mm:ss:SS");

你甚至可以将其内联到以下代码中: DurationFormatUtils.formatDuration(System.currentTimeMillis() - time, "HH:mm:ss:SS"); - Liggy
5
或者使用几乎相同的内置DurationFormatUtils.formatDurationHMS(end-start)函数。 - JRL
@JRL: DurationFormatUtils.formatDurationHMS(end-start); 可以满足问题中提出的例子,但是我在我的解决方案中添加了毫秒。 - Bill the Lizard
2
没错!虽然 formatDurationHMS 不完全符合要求,因为它是 H:m:s 而不是 HH:mm:ss,但我只是想指出它作为一种可能性。 - JRL
这项工作现在可以无需第三方库完成:请参见java.time包中的DurationPeriod类,以表示不附加于时间线的一段时间。 - Basil Bourque

5
一个专门设计的库是更好的方法,但对于小于一天的时间段,使用正确的TimeZoneSimpleDateFormat可能已经足够。更长的时间段需要特殊处理天数。
import java.text.DateFormat;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

public class Elapsed {

    private static final long MS_DAY = 24 * 60 * 60 * 1000;
    private final DateFormat df = new SimpleDateFormat("HH : mm : ss : S");

    public Elapsed() {
        df.setTimeZone(TimeZone.getTimeZone("GMT"));
    }

    private String format(long elapsed) {
        long day = elapsed / MS_DAY;
        StringBuilder sb = new StringBuilder();
        sb.append(day);
        sb.append(" : ");
        sb.append(df.format(new Date(elapsed)));
        return sb.toString();
    }

    public static void main(String[] args) {
        Elapsed e = new Elapsed();
        for (long t = 0; t < 3 * MS_DAY; t += MS_DAY / 2) {
            System.out.println(e.format(t));
        }
    }
}

控制台输出:

0 : 00 : 00 : 00 : 0
0 : 12 : 00 : 00 : 0
1 : 00 : 00 : 00 : 0
1 : 12 : 00 : 00 : 0
2 : 00 : 00 : 00 : 0
2 : 12 : 00 : 00 : 0

4

简而言之

Duration.ofMillis( … )
        .toString()

…或者…

Duration.between(      // `Duration` represents a span of time unattached to the timeline, in a scale of days-hours-minutes-seconds-nanos.
    instantEarlier ,   // Capture the current moment to start.
    Instant.now()      // Capture the current moment now, in UTC.
)                      // Returns a `Duration` object.
.toString()            // Generate a string in standard ISO 8601 format.

PT1M23.407S

ISO 8601

什么是从毫秒派生出的时间格式的最短、最简单、最不废话的写法?

ISO 8601 标准定义了日期时间值的文本格式。这些格式确实是短小、简单和不废话的。它们在各种文化中很容易阅读,实用且无歧义。

对于不与时间轴相关联的时间段,标准格式PnYnMnDTnHnMnSP 标记开始,T 将年-月-日与时-分-秒分开。因此,一个半小时为 PT1H30M

java.time.Duration

Java时间类包含一对用于表示时间跨度的类。Duration类用于表示小时-分钟-秒,而Period类则表示天-月-年。

Instant

Instant类表示时间线上的一个时刻,在UTC中分辨率为纳秒(最多九位小数)。

Instant earlier = Instant.now() ;  // Capture the current moment in UTC.
… 
Instant later = Instant.now() ;

Duration d = Duration.between( earlier , later ) ;
String output = d.toString() ;  

PT3.52S


关于java.time

java.time框架内置于Java 8及更高版本中。这些类替代了旧的、麻烦的传统日期时间类,例如java.util.DateCalendarSimpleDateFormat

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。无需字符串,无需java.sql.*类。

如何获取java.time类?

ThreeTen-Extra项目扩展了java.time的额外类。该项目是java.time可能未来添加的可行性试验场。您可能会在这里找到一些有用的类,例如Interval, YearWeek, YearQuarter以及更多


1

如果您确实想要看到毫秒级别的差异,我认为没有更短、更简单的方法了。

如果您需要一种更强大(但肯定不是更简单)的收集性能统计信息的方式,可以使用Perf4J


1

据我所知,没有这样的函数。但是如果你计算出H、M和S的值,并为每个值使用%02模式,printf()可以轻松地完成此操作。


0
long diff = System.currentTimeMillis() - startTime;
int hours = (int)(diff / 3600000); diff -= hours * 3600000;
int mins = (int)(diff / 60000); diff -= mins * 60000;
int secs = (int)(diff / 1000); diff -= secs * 1000;
System.out.println(String.format("%d:%d:%d.%d", hours, mins, secs, diff));

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