更好的打印mm:ss.ms秒表字符串的方法?

时间:2011-10-04 16:38:21

标签: java

我想显示一个带有分钟,秒和只有一个毫秒字符的格式化字符串。这是我放在一起的(主要来自这里的其他帖子):

public static final String getTimeDurationAsString(long milliseconds) {
    int millis  = (int) (milliseconds % 1000);
    int seconds = (int) (milliseconds / 1000) % 60;
    int minutes = (int) ((milliseconds / (1000*60)) % 60);
    int hours   = (int) ((milliseconds / (1000*60*60)) % 24);

    StringBuilder sb = new StringBuilder();
    if (hours > 0) {
        sb.append(String.format("%02d", hours));
        sb.append(":");
    }
    sb.append(String.format("%02d", minutes));
    sb.append(":");
    sb.append(String.format("%02d", seconds));
    sb.append(".");
    sb.append(String.format("%03d", millis).substring(0, 1));

    return sb.toString();
}

如果持续时间不超过59.9分钟(通常是这种情况),我会隐藏小时位置。我为毫秒位置做了一个非常糟糕的子串()来获取第一个数字。有没有更好的方法来做到这一点?我喜欢这样的字符串:

00:14.9
00:05.1
00:05.2
33:20:4
etc

我必须为我正在制作的游戏重复生成这个字符串(上面每帧渲染一次),所以害怕它做了很多不必要的工作?

谢谢!

4 个答案:

答案 0 :(得分:2)

毫无疑问,有更有效的方法来编写代码(实际上总是存在)。

但是,在我的盒子上,你的功能可以格式化每秒约130,000个时间戳。显然,这足以满足您所述的用例。

那就是说,如果我对此进行编码并认为它​​可能是关键性能路径的先验,我会避免String.format()

public static final String getTimeDurationAsString(long milliseconds) {
    int millis  = (int) (milliseconds % 1000);
    int seconds = (int) (milliseconds / 1000) % 60;
    int minutes = (int) ((milliseconds / (1000*60)) % 60);
    int hours   = (int) ((milliseconds / (1000*60*60)) % 24);
    StringBuilder sb = new StringBuilder();
    if (hours > 0) {
        sb.append((char)('0' + hours / 10))
          .append((char)('0' + hours % 10)).append(":");
    }
    sb.append((char)('0' + minutes / 10))
      .append((char)('0' + minutes % 10)).append(":")
      .append((char)('0' + seconds / 10))
      .append((char)('0' + seconds % 10)).append(".")
      .append((char)('0' + millis / 100));
    return sb.toString();
}

在我的盒子上,每秒可以进行大约800万次转换。它还创建了更少的临时对象,最终不得不进行垃圾回收。

答案 1 :(得分:2)

要将毫秒转换为其他单位,您可以使用TimeUnit

小型演示文稿:

long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis));

String.format("%02d:%02d", minutes, seconds);

但你真正想做的是将毫秒改为简单的日期:

Date date = new Date(milliseconds);
SimpleDateFormat formatter = new SimpleDateFormat("mm:ss.S");
System.out.println(formatter.format(date));

输出:

getTimeDurationAsString(14009) => 00:14.9
getTimeDurationAsString(2000004) => 33:20.4

答案 2 :(得分:0)

您可以使用String.format一次将多个项目格式化为字符串。

public static final String getTimeDurationAsString(long milliseconds) 
{
    int millis  = (int) (milliseconds % 1000);
    int seconds = (int) (milliseconds / 1000) % 60;
    int minutes = (int) ((milliseconds / (1000*60)) % 60);
    int hours   = (int) ((milliseconds / (1000*60*60)) % 24);

    string hours = "";
    if(hours > 0)
        hours = String.format("%02d:", hours);
    return hours + String.format("%0$:%1$:%2$", minutes, seconds, millis / 100);
}

答案 3 :(得分:0)

我认为Joda-Time提供了最干净的解决方案。它可能不是最高效的,因为它非常强大和灵活。但它有适当的类型来表示你正在做的事情的持续时间,这给了它一个非常高效的好机会。

使用Joda-Time就是这么简单:

private static final PeriodType MSM_PERIOD_TYPE = PeriodType.forFields(new DurationFieldType[]{
        DurationFieldType.minutes(),
        DurationFieldType.seconds(),
        DurationFieldType.millis()});

public static String getTimeDurationAsString(long milliseconds) {
    Period period = new Duration(milliseconds).toPeriod(MSM_PERIOD_TYPE);

    return String.format("%02d:%02d.%01d",
            period.getMinutes(),
            period.getSeconds(),
            period.getMillis() / 100);
}

如果您知道这段时间永远不会超过或等于一小时,那么您甚至不需要MSM_PERIOD_TYPE

至于最高性能的解决方案......好吧,我无法想象任何给定的解决方案甚至会成为游戏渲染代码的一个因素。你可以通过避免String.format来节省一点,但这似乎是一个无效的优化,因为它使代码变得多么麻烦。

Joda-Time也有一个PeriodFormatter类(使用PeriodFormatterBuilder构建)但我没有看到像你想要的那样包含十分之一秒的简洁方法。