jnemecz
jnemecz

Reputation: 3608

How to format time intervals in Java?

I create J2SE application and this application needs to format two times in milliseconds into a string that represents the interval between this two times.

long time1 = 1334331041677L; //Fri Apr 13 17:30:41 CEST 2012
long time2 = time1+1000*60*2; //Fri Apr 13 17:32:41 CEST 2012

and I would like to get something like "00:02:00". This would be simple, but I need to format interval which is long from few seconds up to several years - so the library should handle it. Ideally is if this library could format the interval according to the habbits of the country (if any).

I have searched throught the questions and answers and solution for me could be Jodatime or Lang library from Apache Commons. Could you provide me some recommendation which library from these solves my requirements in better way? Thank you in advance.

Upvotes: 3

Views: 9005

Answers (5)

notes-jj
notes-jj

Reputation: 1557

Detailed Answer: https://stackoverflow.com/a/39600534/5330578

Simple formatting for elapsed time less than 24h. Over 24h the code will only display the hours within the next day and won't add the elapsed day to the hours.

public static String formatElapsedTime(long milliseconds) {

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

    return sdf.format(milliseconds);
}

Upvotes: -1

Smig
Smig

Reputation: 693

According to this answer, this is the most efficient way of formatting elapsed time:

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

Upvotes: 0

JiP
JiP

Reputation: 3258

You can use standard Java Calendar for intervals up to one day (24 hours). It is not possible to use this trick for longer periods (days, years), though...

long start = System.currentTimeMillis();
/*
 * perform the measured activity here,
 * let's say it will take 2 minutes 5 seconds => 125 seconds => 125000ms
 */
Thread.sleep(125 * 1000);
long stop = System.currentTimeMillis();
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
c.setTimeInMillis(c.getTimeInMillis() + (stop - start));
DateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
System.out.println(df.format(c.getTime()));

Upvotes: 1

user799188
user799188

Reputation: 14415

If I understood you correctly, the following (using Joda Time) should help

import org.joda.time.DateTime;
import org.joda.time.Period;

private String formatDuration(DateTime dt1, DateTime dt2) {
  Period period = new Period(dt1, dt2);
  String str = String.format("%s:%02d:%02d:%02d:%02d:%02d", 
    period.getYears(), period.getMonths(), period.getDays(), 
    period.getHours(), period.getMinutes(), period.getSeconds());
    // Ignoring milliseconds

  String[] tokens = str.split(":");
  boolean currNonZero = false, flag = false, isFirst = true;
  int ctr = 0, pos = 0;
  StringBuilder sb = new StringBuilder();
  for (String token : tokens) {
    pos++;
    int val = Integer.parseInt(token);
    currNonZero = (val > 0);
    if ((ctr < 3 && (flag || currNonZero)) || (ctr == 0 && pos > 3)) {
      if (isFirst) { isFirst = false; }
      else { sb.append(":"); }
      sb.append(token);
      flag = (++ctr < 3);
    }
  }

  return sb.toString();  
}

A few tests,

DateTime dt1 = new DateTime(2012, 1, 1, 8, 3, 5, 0);
DateTime dt2 = new DateTime(2012, 1, 2, 9, 5, 6, 0);
DateTime dt3 = new DateTime(2012, 2, 3, 11, 3, 5, 0);
DateTime dt4 = new DateTime(2012, 2, 3, 11, 3, 10, 0);
DateTime dt5 = new DateTime(2012, 2, 3, 11, 3, 10, 5); //5 millis away from dt4

formatDuration(dt1, dt2); // Returns "01:01:01"
formatDuration(dt1, dt3); // Returns "01:02:03"
formatDuration(dt3, dt4); // Returns "00:00:05"
formatDuration(dt4, dt5); // Returns "00:00:00"

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500055

PeriodFormat in Joda Time is probably what you want - but you'll need to think very carefully about how you want to format values of more than a day. Bear in mind that months and years are of variable lengths - if you're happy to have the largest unit as a day, that would probably keep things simple.

You should also be aware of the difference in Joda Time between a Period (which can include things like "months") and a Duration which is a fixed number of milliseconds. Normalization between the two touches on exactly the problems mentioned above :) Basically, you should work out whether you're interested in the difference in elapsed time between two instants in time, or the difference in "calendar" time between two local date/time values. For example, between midnight and 2am on a particular date in a particular time zone may be 1 hour, 2 hours or 3 hours of elapsed time...

Upvotes: 1

Related Questions