关于时间:如何在Java中将毫秒转换为“X分钟,x秒”?

How to convert Milliseconds to “X mins, x seconds” in Java?

我想用System.currentTimeMillis()记录用户在我的程序中开始某个操作的时间。当他完成后,我将从start变量中减去当前的System.currentTimeMillis(),我想用人类可读的格式(如"xx小时,xx分钟,xx秒",甚至"xx分钟,xx秒")向他们显示所用的时间,因为它不可能花费一个小时。

最好的方法是什么?


使用java.util.concurrent.TimeUnit类:

1
2
3
4
5
String.format("%d min, %d sec",
    TimeUnit.MILLISECONDS.toMinutes(millis),
    TimeUnit.MILLISECONDS.toSeconds(millis) -
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
);

注意:EDCOX1 OR 1是Java 1.5规范的一部分,但是EDCOX1 OR 2 2被添加为Java 1.6。

要为值0-9添加前导零,只需执行以下操作:

1
2
3
4
5
String.format("%02d min, %02d sec",
    TimeUnit.MILLISECONDS.toMinutes(millis),
    TimeUnit.MILLISECONDS.toSeconds(millis) -
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
);

如果不支持TimeUnittoMinutes(例如在API 9版之前的Android上),请使用以下公式:

1
2
3
4
int seconds = (int) (milliseconds / 1000) % 60 ;
int minutes = (int) ((milliseconds / (1000*60)) % 60);
int hours   = (int) ((milliseconds / (1000*60*60)) % 24);
//etc...


基于@siddhadev的答案,我编写了一个函数,将毫秒转换为格式化字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   /**
     * Convert a millisecond duration to a string format
     *
     * @param millis A duration to convert to a string form
     * @return A string of the form"X Days Y Hours Z Minutes A Seconds".
     */

    public static String getDurationBreakdown(long millis) {
        if(millis < 0) {
            throw new IllegalArgumentException("Duration must be greater than zero!");
        }

        long days = TimeUnit.MILLISECONDS.toDays(millis);
        millis -= TimeUnit.DAYS.toMillis(days);
        long hours = TimeUnit.MILLISECONDS.toHours(millis);
        millis -= TimeUnit.HOURS.toMillis(hours);
        long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
        millis -= TimeUnit.MINUTES.toMillis(minutes);
        long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);

        StringBuilder sb = new StringBuilder(64);
        sb.append(days);
        sb.append(" Days");
        sb.append(hours);
        sb.append(" Hours");
        sb.append(minutes);
        sb.append(" Minutes");
        sb.append(seconds);
        sb.append(" Seconds");

        return(sb.toString());
    }


1
2
3
long time = 1536259;

return (new SimpleDateFormat("mm:ss:SSS")).format(new Date(time));

印刷品:

25:36:259


嗯…一秒钟有多少毫秒?一分钟后呢?划分并不难。

1
2
int seconds = (int) ((milliseconds / 1000) % 60);
int minutes = (int) ((milliseconds / 1000) / 60);

像这样持续几个小时,几天,几周,几个月,一年,几十年,不管怎样。


我不会仅仅因为这个而引入额外的依赖关系(毕竟划分并不那么难),但是如果您仍然使用commons-lang,那么就有durationformatuils。


在Java 8中使用Java.TimePosits:

1
2
3
4
Instant start = Instant.now();
Thread.sleep(63553);
Instant end = Instant.now();
System.out.println(Duration.between(start, end));

输出采用ISO 8601持续时间格式:PT1M3.553S(1分3.553秒)。


或者手动划分,或者使用SimpleDateFormat API。

1
2
3
4
5
6
long start = System.currentTimeMillis();
// do your work...
long elapsed = System.currentTimeMillis() - start;
DateFormat df = new SimpleDateFormat("HH 'hours', mm 'mins,' ss 'seconds'");
df.setTimeZone(TimeZone.getTimeZone("GMT+0"));
System.out.println(df.format(new Date(elapsed)));

由bombe编辑:评论中显示这种方法只适用于较小的持续时间(即少于一天)。


只是为了添加更多信息如果要格式化为:hh:mm:ss

0<=hh<=无限

0<mm<60

0<SS<60

使用此:

1
2
3
int h = (int) ((startTimeInMillis / 1000) / 3600);
int m = (int) (((startTimeInMillis / 1000) / 60) % 60);
int s = (int) ((startTimeInMillis / 1000) % 60);

我刚刚有了这个问题,并解决了这个问题


我认为最好的办法是:

1
2
3
String.format("%d min, %d sec",
    TimeUnit.MILLISECONDS.toSeconds(length)/60,
    TimeUnit.MILLISECONDS.toSeconds(length) % 60 );


最短解决方案:

这里可能是最短的,也涉及时区。

1
System.out.printf("%tT", millis-TimeZone.getDefault().getRawOffset());

哪些输出,例如:

1
00:18:32

说明:

%tT是24小时制时钟的时间格式,如%tH:%tM:%tS所示。

%tT也接受long作为输入,因此不需要创建Dateprintf()只打印以毫秒为单位的时间,但在当前时区,因此我们必须减去当前时区的原始偏移量,使0毫秒为0小时,而不是当前时区的时间偏移值。

注1:如果您需要String的结果,您可以这样得到:

1
String t = String.format("%tT", millis-TimeZone.getDefault().getRawOffset());

注2:这仅在millis小于一天时给出正确的结果,因为日部分不包括在输出中。


乔达时间

使用Joda时间:

1
2
3
4
5
6
7
8
DateTime startTime = new DateTime();

// do something

DateTime endTime = new DateTime();
Duration duration = new Duration(startTime, endTime);
Period period = duration.toPeriod().normalizedStandard(PeriodType.time());
System.out.println(PeriodFormat.getDefault().print(period));


重新访问@brent nash contribution,我们可以使用模量函数而不是减法,并对结果字符串使用string.format方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /**
   * Convert a millisecond duration to a string format
   *
   * @param millis A duration to convert to a string form
   * @return A string of the form"X Days Y Hours Z Minutes A Seconds B Milliseconds".
   */

   public static String getDurationBreakdown(long millis) {
       if (millis < 0) {
          throw new IllegalArgumentException("Duration must be greater than zero!");
       }

       long days = TimeUnit.MILLISECONDS.toDays(millis);
       long hours = TimeUnit.MILLISECONDS.toHours(millis) % 24;
       long minutes = TimeUnit.MILLISECONDS.toMinutes(millis) % 60;
       long seconds = TimeUnit.MILLISECONDS.toSeconds(millis) % 60;
       long milliseconds = millis % 1000;

       return String.format("%d Days %d Hours %d Minutes %d Seconds %d Milliseconds",
                            days, hours, minutes, seconds, milliseconds);
   }

对于低于API 9的Android

1
(String.format("%d hr %d min, %d sec", millis/(1000*60*60), (millis%(1000*60*60))/(1000*60), ((millis%(1000*60*60))%(1000*60))/1000))

对于不到一小时的小时间,我更喜欢:

1
2
3
4
5
long millis = ...

System.out.printf("%1$TM:%1$TS", millis);
// or
String str = String.format("%1$TM:%1$TS", millis);

对于较长的间隔:

1
2
3
4
5
6
7
private static final long HOUR = TimeUnit.HOURS.toMillis(1);
...
if (millis < HOUR) {
    System.out.printf("%1$TM:%1$TS%n", millis);
} else {
    System.out.printf("%d:%2$TM:%2$TS%n", millis / HOUR, millis % HOUR);
}


我的简单计算:

1
2
3
4
5
6
7
8
9
10
11
String millisecToTime(int millisec) {
    int sec = millisec/1000;
    int second = sec % 60;
    int minute = sec / 60;
    if (minute >= 60) {
        int hour = minute / 60;
        minute %= 60;
        return hour +":" + (minute < 10 ?"0" + minute : minute) +":" + (second < 10 ?"0" + second : second);
    }
    return minute +":" + (second < 10 ?"0" + second : second);
}

快乐编码:


1
2
3
4
5
6
7
8
9
10
    long startTime = System.currentTimeMillis();
    // do your work...
    long endTime=System.currentTimeMillis();
    long diff=endTime-startTime;      
    long hours=TimeUnit.MILLISECONDS.toHours(diff);
    diff=diff-(hours*60*60*1000);
    long min=TimeUnit.MILLISECONDS.toMinutes(diff);
    diff=diff-(min*60*1000);
    long seconds=TimeUnit.MILLISECONDS.toSeconds(diff);
    //hour, min and seconds variables contains the time elapsed on your work


这在Java 9中更容易:

1
2
3
4
5
6
    Duration elapsedTime = Duration.ofMillis(millisDiff );
    String humanReadableElapsedTime = String.format(
           "%d hours, %d mins, %d seconds",
            elapsedTime.toHours(),
            elapsedTime.toMinutesPart(),
            elapsedTime.toSecondsPart());

这会产生一个类似于0 hours, 39 mins, 9 seconds的字符串。

如果要在格式化前舍入到整秒:

1
    elapsedTime = elapsedTime.plusMillis(500).truncatedTo(ChronoUnit.SECONDS);

如果小时数为0,则不计算小时数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    long hours = elapsedTime.toHours();
    String humanReadableElapsedTime;
    if (hours == 0) {
        humanReadableElapsedTime = String.format(
               "%d mins, %d seconds",
                elapsedTime.toMinutesPart(),
                elapsedTime.toSecondsPart());

    } else {
        humanReadableElapsedTime = String.format(
               "%d hours, %d mins, %d seconds",
                hours,
                elapsedTime.toMinutesPart(),
                elapsedTime.toSecondsPart());
    }

现在我们可以有例如39 mins, 9 seconds

要以零开头打印分钟和秒,使它们始终为两位数,只需将02插入相关的格式说明符,这样:

1
2
3
4
5
    String humanReadableElapsedTime = String.format(
           "%d hours, %02d mins, %02d seconds",
            elapsedTime.toHours(),
            elapsedTime.toMinutesPart(),
            elapsedTime.toSecondsPart());

现在我们可以有例如0 hours, 39 mins, 09 seconds


下面是一个基于布伦特·纳什答案的答案,希望能有所帮助!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static String getDurationBreakdown(long millis)
{
    String[] units = {" Days"," Hours"," Minutes"," Seconds"};
    Long[] values = new Long[units.length];
    if(millis < 0)
    {
        throw new IllegalArgumentException("Duration must be greater than zero!");
    }

    values[0] = TimeUnit.MILLISECONDS.toDays(millis);
    millis -= TimeUnit.DAYS.toMillis(values[0]);
    values[1] = TimeUnit.MILLISECONDS.toHours(millis);
    millis -= TimeUnit.HOURS.toMillis(values[1]);
    values[2] = TimeUnit.MILLISECONDS.toMinutes(millis);
    millis -= TimeUnit.MINUTES.toMillis(values[2]);
    values[3] = TimeUnit.MILLISECONDS.toSeconds(millis);

    StringBuilder sb = new StringBuilder(64);
    boolean startPrinting = false;
    for(int i = 0; i < units.length; i++){
        if( !startPrinting && values[i] != 0)
            startPrinting = true;
        if(startPrinting){
            sb.append(values[i]);
            sb.append(units[i]);
        }
    }

    return(sb.toString());
}

有个问题。当毫秒数为59999时,实际上是1分钟,但它将被计算为59秒,并丢失999毫秒。

这里有一个基于以前答案的修改版本,可以解决这个损失:

1
2
3
4
5
6
7
8
9
10
public static String formatTime(long millis) {
    long seconds = Math.round((double) millis / 1000);
    long hours = TimeUnit.SECONDS.toHours(seconds);
    if (hours > 0)
        seconds -= TimeUnit.HOURS.toSeconds(hours);
    long minutes = seconds > 0 ? TimeUnit.SECONDS.toMinutes(seconds) : 0;
    if (minutes > 0)
        seconds -= TimeUnit.MINUTES.toSeconds(minutes);
    return hours > 0 ? String.format("%02d:%02d:%02d", hours, minutes, seconds) : String.format("%02d:%02d", minutes, seconds);
}


如果您知道时差小于一小时,则可以使用以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    Calendar c1 = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();

    c2.add(Calendar.MINUTE, 51);

    long diff = c2.getTimeInMillis() - c1.getTimeInMillis();

    c2.set(Calendar.MINUTE, 0);
    c2.set(Calendar.HOUR, 0);
    c2.set(Calendar.SECOND, 0);

    DateFormat df = new SimpleDateFormat("mm:ss");
    long diff1 = c2.getTimeInMillis() + diff;
    System.out.println(df.format(new Date(diff1)));

结果是:51:00


对于正确的字符串("1小时,3秒","3分钟",但不是"0小时,0分钟,3秒"),我编写此代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int seconds = (int)(millis / 1000) % 60 ;
int minutes = (int)((millis / (1000*60)) % 60);
int hours = (int)((millis / (1000*60*60)) % 24);
int days = (int)((millis / (1000*60*60*24)) % 365);
int years = (int)(millis / 1000*60*60*24*365);

ArrayList<String> timeArray = new ArrayList<String>();

if(years > 0)  
    timeArray.add(String.valueOf(years)   +"y");

if(days > 0)    
    timeArray.add(String.valueOf(days) +"d");

if(hours>0)  
    timeArray.add(String.valueOf(hours) +"h");

if(minutes>0)
    timeArray.add(String.valueOf(minutes) +"min");

if(seconds>0)
    timeArray.add(String.valueOf(seconds) +"sec");

String time ="";
for (int i = 0; i < timeArray.size(); i++)
{
    time = time + timeArray.get(i);
    if (i != timeArray.size() - 1)
        time = time +",";
}

if (time =="")
  time ="0 sec";

这个答案与上面的一些答案类似。但是,我觉得这是有益的,因为与其他答案不同,这将删除任何多余的逗号或空格,并处理缩写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
 * Converts milliseconds to"x days, x hours, x mins, x secs"
 *
 * @param millis
 *            The milliseconds
 * @param longFormat
 *            {@code true} to use"seconds" and"minutes" instead of"secs" and"mins"
 * @return A string representing how long in days/hours/minutes/seconds millis is.
 */

public static String millisToString(long millis, boolean longFormat) {
    if (millis < 1000) {
        return String.format("0 %s", longFormat ?"seconds" :"secs");
    }
    String[] units = {
           "day","hour", longFormat ?"minute" :"min", longFormat ?"second" :"sec"
    };
    long[] times = new long[4];
    times[0] = TimeUnit.DAYS.convert(millis, TimeUnit.MILLISECONDS);
    millis -= TimeUnit.MILLISECONDS.convert(times[0], TimeUnit.DAYS);
    times[1] = TimeUnit.HOURS.convert(millis, TimeUnit.MILLISECONDS);
    millis -= TimeUnit.MILLISECONDS.convert(times[1], TimeUnit.HOURS);
    times[2] = TimeUnit.MINUTES.convert(millis, TimeUnit.MILLISECONDS);
    millis -= TimeUnit.MILLISECONDS.convert(times[2], TimeUnit.MINUTES);
    times[3] = TimeUnit.SECONDS.convert(millis, TimeUnit.MILLISECONDS);
    StringBuilder s = new StringBuilder();
    for (int i = 0; i < 4; i++) {
        if (times[i] > 0) {
            s.append(String.format("%d %s%s,", times[i], units[i], times[i] == 1 ?"" :"s"));
        }
    }
    return s.toString().substring(0, s.length() - 2);
}

/**
 * Converts milliseconds to"x days, x hours, x mins, x secs"
 *
 * @param millis
 *            The milliseconds
 * @return A string representing how long in days/hours/mins/secs millis is.
 */

public static String millisToString(long millis) {
    return millisToString(millis, false);
}

我在另一个答案中对此进行了讨论,但您可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) {
    long diffInMillies = date2.getTime() - date1.getTime();
    List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class));
    Collections.reverse(units);
    Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
    long milliesRest = diffInMillies;
    for ( TimeUnit unit : units ) {
        long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
        long diffInMilliesForUnit = unit.toMillis(diff);
        milliesRest = milliesRest - diffInMilliesForUnit;
        result.put(unit,diff);
    }
    return result;
}

输出类似于Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0},单位已订购。

由您决定如何根据目标区域设置将这些数据国际化。


使用java.util.concurrent.timeUnit,并使用以下简单方法:

1
2
3
4
5
private static long timeDiff(Date date, Date date2, TimeUnit unit) {
    long milliDiff=date2.getTime()-date.getTime();
    long unitDiff = unit.convert(milliDiff, TimeUnit.MILLISECONDS);
    return unitDiff;
}

例如:

1
2
3
4
5
6
7
8
9
SimpleDateFormat sdf = new SimpleDateFormat("yy/MM/dd HH:mm:ss");  
Date firstDate = sdf.parse("06/24/2017 04:30:00");
Date secondDate = sdf.parse("07/24/2017 05:00:15");
Date thirdDate = sdf.parse("06/24/2017 06:00:15");

System.out.println("days difference:"+timeDiff(firstDate,secondDate,TimeUnit.DAYS));
System.out.println("hours difference:"+timeDiff(firstDate,thirdDate,TimeUnit.HOURS));
System.out.println("minutes difference:"+timeDiff(firstDate,thirdDate,TimeUnit.MINUTES));
System.out.println("seconds difference:"+timeDiff(firstDate,thirdDate,TimeUnit.SECONDS));


我修改了@mykullski的答案并添加了增强支持。我用了几秒钟,因为我不需要它们,不过如果你需要的话,可以随意地重新添加。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public static String intervalToHumanReadableTime(int intervalMins) {

    if(intervalMins <= 0) {
        return"0";
    } else {

        long intervalMs = intervalMins * 60 * 1000;

        long days = TimeUnit.MILLISECONDS.toDays(intervalMs);
        intervalMs -= TimeUnit.DAYS.toMillis(days);
        long hours = TimeUnit.MILLISECONDS.toHours(intervalMs);
        intervalMs -= TimeUnit.HOURS.toMillis(hours);
        long minutes = TimeUnit.MILLISECONDS.toMinutes(intervalMs);

        StringBuilder sb = new StringBuilder(12);

        if (days >= 1) {
            sb.append(days).append(" day").append(pluralize(days)).append(",");
        }

        if (hours >= 1) {
            sb.append(hours).append(" hour").append(pluralize(hours)).append(",");
        }

        if (minutes >= 1) {
            sb.append(minutes).append(" minute").append(pluralize(minutes));
        } else {
            sb.delete(sb.length()-2, sb.length()-1);
        }

        return(sb.toString());          

    }

}

public static String pluralize(long val) {
    return (Math.round(val) > 1 ?"s" :"");
}