如何将毫秒转换为“hh:mm:ss”格式?

226
我有点困惑。在偶然看到这个帖子后,我尝试着弄清楚如何格式化一个倒计时器,使其呈现出hh:mm:ss的格式。
以下是我的尝试 -
//hh:mm:ss
String.format("%02d:%02d:%02d", 
    TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) - 
    TimeUnit.MINUTES.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
    TimeUnit.MILLISECONDS.toSeconds(millis) - 
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));   
所以,当我尝试使用值3600000ms时,我得到了01:59:00,这是错误的,因为它应该是01:00:00。很明显我的逻辑有问题,但目前我看不出来错在哪里!
有人能帮忙吗?
编辑 -
已经解决了。以下是将毫秒格式化为hh:mm:ss格式的正确方法 -
//hh:mm:ss
String.format("%02d:%02d:%02d", 
    TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) - 
    TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
    TimeUnit.MILLISECONDS.toSeconds(millis) - 
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))));

问题出在这里 TimeUnit.MINUTES.toMinutes(TimeUnit.MILLISECONDS.toHours(millis))。正确的应该是 TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis))


1
3600000毫秒等于3600秒,或60分钟,或1小时。它不应该是00:59:59,而应该是01:00:00 - Borealid
19个回答

418

你已经非常接近了:

String.format("%02d:%02d:%02d", 
TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis) -  
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), // The change is in this line
TimeUnit.MILLISECONDS.toSeconds(millis) - 
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));   

您使用分钟而不是小时将小时转换为毫秒。

顺便说一下,我喜欢您使用TimeUnit API的方式 :)

这里是一些测试代码:

public static void main(String[] args) throws ParseException {
    long millis = 3600000;
    String hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
            TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
    System.out.println(hms);
}

输出:

01:00:00
我意识到可以使用模运算而不是减法大大简化我的代码:
String hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) % TimeUnit.HOURS.toMinutes(1),
    TimeUnit.MILLISECONDS.toSeconds(millis) % TimeUnit.MINUTES.toSeconds(1));

仍然对所有魔法值使用TimeUnit API,并产生完全相同的输出。


2
重复造轮子并不是一个好主意!Triton Man的答案是更好的解决方案。 - محمدباقر
6
但是另一个答案使用了外部库,而我的代码只使用了核心JDK。这取决于您的需求-例如,您可能无法使用外部库。不过,另一个答案也很不错。 - Bohemian
超过365天怎么办?你能把它转化成几年吗?谢谢。 - KarenAnne
2
@Ozuf 添加 .replaceAll("^00:", "").replaceAll("^00:(00:)?", "") 来删除分钟和小时,如果两者都为零。 - Bohemian
2
@Ozuf,你分别得到了“15:00”和“10:00:23”;只有前导零被删除,因为匹配被锚定到输入的开头。 - Bohemian
显示剩余6条评论

98

这个的通用方法非常简单:

public static String convertSecondsToHMmSs(long seconds) {
    long s = seconds % 60;
    long m = (seconds / 60) % 60;
    long h = (seconds / (60 * 60)) % 24;
    return String.format("%d:%02d:%02d", h,m,s);
}

1
@Javaman59,你是不是想说 String.format("% 02 d:%02d:%02d", h,m,s) - KarenAnne
2
@KarenAnne。这取决于您想要“03:59:59”还是“3:59:59”。 - Stephen Hosking
3
时间单位为毫秒,需将秒数乘以1000转换。 - Apurva
9
作者询问的是毫秒,而不是秒! - user924

71

如果您正在使用Apache Commons:

DurationFormatUtils.formatDuration(timeInMS, "HH:mm:ss,SSS");

6
快捷方式:DurationFormatUtils.formatDurationHMS(timeInMS);,将毫秒数格式化为hh:mm:ss的时间格式。 - Aroniaina
@Jorgesys 为什么它们已经过时了? - Piovezan
1
它们并不过时。 - Rocky Pulley

31

我用了这个:

String.format("%1$tH:%1$tM:%1$tS.%1$tL", millis);

查看 Formatter 类的描述。

查看使用 2400 毫秒输入的 可运行示例


似乎不起作用,我只是通过传递100、1000、1200进行测试,它的响应为_05:30:00_,_05:30:01_,_05:30:01_。 - CoDe
2
@CoDe,它适用于您的时区。 您必须处于与UTC不同的时区。 String.format()依赖于时区。但是,理想的正确答案应该是与时区无关的。 - Derek Mahar
@CoDe,它显示的时间对应于您的时区,这必须与UTC不同。String.format()是时区相关的。然而,理想的正确答案应该是时区无关的。 - Derek Mahar

29
// New date object from millis
Date date = new Date(millis);
// formattter 
SimpleDateFormat formatter= new SimpleDateFormat("HH:mm:ss.SSS");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
// Pass date object
String formatted = formatter.format(date );

你也可以使用新的日期时间 API

     var formatted = DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
            .withZone(ZoneId.of("UTC"))
            .format(Instant.ofEpochMilli(millis));

3
如果时间超过一天,这将产生错误的结果。它会把小时数从23回绕到0,这可能不是这里想要的。 - Kenster
不,我认为它仍然会起作用。尝试使用今天的日期。 - Vinay Lodha
1
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm aa"); 如果有人想要12小时制的am/pm格式 - Ajji

16
DateFormat df = new SimpleDateFormat("HH:mm:ss");
String formatted = df.format(aDateObject);

1
与 https://dev59.com/lGox5IYBdhLWcg3wsGaC#24327049 相同的答案,但对于超过1天的持续时间存在相同的问题。 - OneWorld
它还取决于时区,这意味着在不同的时区运行时结果会有所不同。 - Derek Mahar

14

这对我有用,使用 Kotlin 实现。

fun formatToDigitalClock(miliSeconds: Long): String {
        val hours = TimeUnit.MILLISECONDS.toHours(miliSeconds).toInt() % 24
        val minutes = TimeUnit.MILLISECONDS.toMinutes(miliSeconds).toInt() % 60
        val seconds = TimeUnit.MILLISECONDS.toSeconds(miliSeconds).toInt() % 60
        return when {
            hours > 0 -> String.format("%d:%02d:%02d", hours, minutes, seconds)
            minutes > 0 -> String.format("%02d:%02d", minutes, seconds)
            seconds > 0 -> String.format("00:%02d", seconds)
            else -> {
                "00:00"
            }
        }
    }

对我来说完美地解决了问题。这应该是最佳答案,因为它处理了零小时的情况。 - vNext

11

Java 9

    Duration timeLeft = Duration.ofMillis(3600000);
    String hhmmss = String.format("%02d:%02d:%02d", 
            timeLeft.toHours(), timeLeft.toMinutesPart(), timeLeft.toSecondsPart());
    System.out.println(hhmmss);

这将打印出:

01:00:00

你做得很对,让库方法为你处理涉及的转换。 java.time,现代Java日期和时间API,更确切地说,它的Duration类比TimeUnit更优雅且更少容易出错。

我使用的toMinutesParttoSecondsPart方法是在Java 9中引入的。

Java 6、7和8

    long hours = timeLeft.toHours();
    timeLeft = timeLeft.minusHours(hours);
    long minutes = timeLeft.toMinutes();
    timeLeft = timeLeft.minusMinutes(minutes);
    long seconds = timeLeft.toSeconds();
    String hhmmss = String.format("%02d:%02d:%02d", hours, minutes, seconds);
    System.out.println(hhmmss);

输出与上面相同。

问题:Java6和7如何使用此功能?

  • 在Java 8及更高版本以及新一代的Android设备(从API级别26开始,我被告知)中,java.time已经内置。
  • 在Java 6和7中,需要获取ThreeTen Backport,即现代类的后移版本(JSR 310的ThreeTen;请参见底部链接)。
  • 在(旧版本)Android中,请使用ThreeTen Backport的Android版。它称为ThreeTenABP。并确保从org.threeten.bp及其子包导入日期和时间类。

链接


11

4个实现的测试结果

因为需要对大量数据进行格式化,所以需要最佳性能,以下是(令人惊讶的)结果:

for (int i = 0; i < 1000000; i++) { FUNCTION_CALL }

时长:

  • combinationFormatter: 196 毫秒
  • formatDuration: 272 毫秒
  • apacheFormat: 754 毫秒
  • formatTimeUnit: 2216 毫秒

    public static String apacheFormat(long millis) throws ParseException {
        return DurationFormatUtils.formatDuration(millis, "HH:mm:ss");
    }
    
    public static String formatTimeUnit(long millis) throws ParseException {
    String formatted = String.format(
            "%02d:%02d:%02d",
            TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis)
                    - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
            TimeUnit.MILLISECONDS.toSeconds(millis)
                    - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
        return formatted;
    }
    
    public static String formatDuration(final long millis) {
        long seconds = (millis / 1000) % 60;
        long minutes = (millis / (1000 * 60)) % 60;
        long hours = millis / (1000 * 60 * 60);
    
        StringBuilder b = new StringBuilder();
        b.append(hours == 0 ? "00" : hours < 10 ? String.valueOf("0" + hours) : 
        String.valueOf(hours));
        b.append(":");
        b.append(minutes == 0 ? "00" : minutes < 10 ? String.valueOf("0" + minutes) :     
        String.valueOf(minutes));
        b.append(":");
        b.append(seconds == 0 ? "00" : seconds < 10 ? String.valueOf("0" + seconds) : 
        String.valueOf(seconds));
        return b.toString();
    }
    
    public static String combinationFormatter(final long millis) {
        long seconds = TimeUnit.MILLISECONDS.toSeconds(millis)
                - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis));
        long minutes = TimeUnit.MILLISECONDS.toMinutes(millis)
                - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis));
        long hours = TimeUnit.MILLISECONDS.toHours(millis);
    
        StringBuilder b = new StringBuilder();
        b.append(hours == 0 ? "00" : hours < 10 ? String.valueOf("0" + hours) : 
        String.valueOf(hours));
        b.append(":");
        b.append(minutes == 0 ? "00" : minutes < 10 ? String.valueOf("0" + minutes) : 
        String.valueOf(minutes));
            b.append(":");
        b.append(seconds == 0 ? "00" : seconds < 10 ? String.valueOf("0" + seconds) : 
        String.valueOf(seconds));
        return b.toString(); 
     }
    

这些指标有多可靠?我从未真正理解过这个过程。 - mre
在我的情况下,连续创建数千个对象,我认为这个测试非常有用。好的,不仅仅是设置一些字符串,而是创建具有一个格式化字符串字段的对象。 - MariusA
@marius,你费心使用了StringBuilder,然后却犯了“0”+数字这种错误,有点“毁掉”了。@mre JVM的GC非常擅长分配和收集大量短暂存在的对象,不用担心。我选择了String.format,无需处理前导零逻辑。 - escape-llc

9
标记为正确的答案有一个小错误,
String myTime = String.format("%02d:%02d:%02d",
            TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis) -
                    TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), // The change is in this line
            TimeUnit.MILLISECONDS.toSeconds(millis) -
                    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));

例如,这是我获得的一个值的示例:
417474:44:19

这是获取正确格式的解决方案:
String myTime =  String.format("%02d:%02d:%02d",
                //Hours
                TimeUnit.MILLISECONDS.toHours(millis) -
                        TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(millis)),
                //Minutes
                TimeUnit.MILLISECONDS.toMinutes(millis) -
                        TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                //Seconds
                TimeUnit.MILLISECONDS.toSeconds(millis) -
                        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));

得到一个正确的格式作为结果:
18:44:19

获取格式为hh:mm:ss的另一种选项是:

   Date myDate = new Date(timeinMillis);
   SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
   String myTime = formatter.format(myDate);

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