如何在Java中格式化hh:mm:ss.SSS格式的经过时间间隔?

问题描述 投票:33回答:12

我正在制作一个秒表,我正在使用Java的SimpleDateFormat将毫秒数转换成一个漂亮的“hh:mm:ss:SSS”格式。问题是小时字段总是有一些随机数。这是我正在使用的代码:

public static String formatTime(long millis) {
    SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");

    String strDate = sdf.format(millis);
    return strDate;
}

如果我脱掉hh部分那么它工作正常。否则在hh部分,即使传入的参数(毫秒数)为零,它也会显示随机的内容,如“07”。

我对SimpleDateFormat类知之甚少。谢谢你的帮助。

java time simpledateformat
12个回答
6
投票

以下是我使用标准JDK的方法(通过将StringBuilder更改回StringBuffer,这可以用于Java 1.1):

static public String formatMillis(long val) {
    StringBuilder                       buf=new StringBuilder(20);
    String                              sgn="";

    if(val<0) { sgn="-"; val=Math.abs(val); }

    append(buf,sgn,0,(val/3600000)); val%=3600000;
    append(buf,":",2,(val/  60000)); val%=  60000;
    append(buf,":",2,(val/   1000)); val%=   1000;
    append(buf,".",3,(val        ));
    return buf.toString();
    }

/** Append a right-aligned and zero-padded numeric value to a `StringBuilder`. */
static private void append(StringBuilder tgt, String pfx, int dgt, long val) {
    tgt.append(pfx);
    if(dgt>1) {
        int pad=(dgt-1);
        for(long xa=val; xa>9 && pad>0; xa/=10) { pad--;           }
        for(int  xa=0;   xa<pad;        xa++  ) { tgt.append('0'); }
        }
    tgt.append(val);
    }

0
投票

变体:最多24小时

经过时间少于24小时的简单格式。超过24小时,代码将仅显示第二天的小时数,并且不会将经过的日期添加到小时。

public static String formatElapsedTime(long milliseconds) {

    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

    return sdf.format(milliseconds);
}

示例代码中缺少功能:

  • 用“UTC”消除时区
  • 使用24小时格式“HH”

变种:超过24小时

public static String formatElapsedTimeOver24h(long milliseconds) {

    // Compiler will take care of constant arithmetics
    if (24 * 60 * 60 * 1000 > milliseconds) {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

        return sdf.format(milliseconds);

    } else {
        SimpleDateFormat sdf = new SimpleDateFormat(":mm:ss.SSS");
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

        // Keep long data type
        // Compiler will take care of constant arithmetics
        long hours = milliseconds / (60L * 60L * 1000L);

        return hours + sdf.format(milliseconds);
    }
}

0
投票

这是另一种方法。完全独立且完全向后兼容。无限天数。

private static String slf(double n) {
  return String.valueOf(Double.valueOf(Math.floor(n)).longValue());
}

public static String timeSpan(long timeInMs) {
  double t = Double.valueOf(timeInMs);
  if(t < 1000d)
    return slf(t) + "ms";
  if(t < 60000d)
    return slf(t / 1000d) + "s " +
      slf(t % 1000d) + "ms";
  if(t < 3600000d)
    return slf(t / 60000d) + "m " +
      slf((t % 60000d) / 1000d) + "s " +
      slf(t % 1000d) + "ms";
  if(t < 86400000d)
    return slf(t / 3600000d) + "h " +
      slf((t % 3600000d) / 60000d) + "m " +
      slf((t % 60000d) / 1000d) + "s " +
      slf(t % 1000d) + "ms";
  return slf(t / 86400000d) + "d " +
    slf((t % 86400000d) / 3600000d) + "h " +
    slf((t % 3600000d) / 60000d) + "m " +
    slf((t % 60000d) / 1000d) + "s " +
    slf(t % 1000d) + "ms";
}

0
投票

这个实际上有效,但似乎我正在调整方法的意图:-)。

public static String formatTime(long millis) {
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");

    String strDate = sdf.format(millis - 3600000);
    return strDate;
}

对于那些真正了解其工作原理的人,您可能会发现一些警告。


68
投票

Support for what you want to do is built in to the latest JDKs with a little known class called TimeUnit.

您想要使用的是java.util.concurrent.TimeUnit以间隔工作。

SimpleDateFormat就像它听起来那样,它会格式化java.util.Date的实例,或者在你的情况下它将long值转换为java.util.Date的上下文并且它不知道如何处理间隔,这是你显然正在使用的。

您可以轻松地执行此操作,而无需使用JodaTime等外部库。

import java.util.concurrent.TimeUnit;

public class Main
{        
    private static String formatInterval(final long l)
    {
        final long hr = TimeUnit.MILLISECONDS.toHours(l);
        final long min = TimeUnit.MILLISECONDS.toMinutes(l - TimeUnit.HOURS.toMillis(hr));
        final long sec = TimeUnit.MILLISECONDS.toSeconds(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
        final long ms = TimeUnit.MILLISECONDS.toMillis(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec));
        return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
    }

    public static void main(final String[] args)
    {
        System.out.println(formatInterval(Long.parseLong(args[0])));
    }
}

输出将格式化为这样

13:00:00.000

28
投票

更简单的方法是在DurationFormatUtils中使用Apache Commons Lang类:

public static String formatTime(long millis) {
    return DurationFormatUtils.formatDuration(millis, "HH:mm:ss.S");
}

6
投票

为什么不呢?

public static String GetFormattedInterval(final long ms) {
    long millis = ms % 1000;
    long x = ms / 1000;
    long seconds = x % 60;
    x /= 60;
    long minutes = x % 60;
    x /= 60;
    long hours = x % 24;

    return String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, millis);
}

5
投票

这是Joda工作的第一部分,我已经完成了比JDK支持更繁琐的工作。请求格式的Joda实现(对零字段做出一些假设)是:

public void printDuration(long milliSecs)
{
    PeriodFormatter formatter = new PeriodFormatterBuilder()
        .printZeroIfSupported()
        .appendHours()
        .appendSeparator(":")
        .minimumPrintedDigits(2)
        .appendMinutes()
        .appendSeparator(":")
        .appendSecondsWithMillis()
        .toFormatter();

    System.out.println(formatter.print(new Period(milliSecs)));
}

3
投票

回顾其他答案,我想出了这个功能......

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

2
投票

这是正在发生的事情。当您传递毫秒时,该数字相对于1970年1月1日。当您传递0时,它将获取该日期并将其转换为您当地的时区。如果你在中部时间那么恰好是晚上7点。如果你运行它,那一切都有意义。

new SimpleDateFormat().format(0) => 12/31/69 7:00 PM

编辑,我想你想要做的是获得经过的时间。为此,我建议使用JodaTime,它已经做得非常好。你做的事情

PeriodFormatter formatter = new PeriodFormatterBuilder()
    .appendHours()
    .appendSuffix(" hour", " hours")
    .appendSeparator(" and ")
    .appendMinutes()
    .appendSuffix(" minute", " minutes")
    .appendSeparator(" and ")
    .appendSeconds()
    .appendSuffix(" second", " seconds")
    .toFormatter();

String formattedText = formatter.print(new Period(elapsedMilliSeconds));

1
投票

格式根据您当地的时区发生,因此如果您传递0,则假设为0 GMT,然后在您当地的时区进行转换。


0
投票

使用普通的Java Calendar间隔最多一天(24小时),请看我对这个问题的回答:How to format time intervals in Java?

© www.soinside.com 2019 - 2024. All rights reserved.