3

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.

Artegon
  • 2,734
  • 6
  • 32
  • 62

5 Answers5

1

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...

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • 1) I searched Jogatime API what I could but I could not find a way to get a formatted value in proper way when is greater than 24hours. E.g. if the difference is 2 days, 3 hours, 12 minutes and 10 seconds this should returns "51:12:10" and not "02:03:12:10". 2) What is the actually formatted correctly time interval? "51:12:10" or "02:03:12:10"? Does it solve some kind of prescription or it depends on each programmer's needs? – Artegon Apr 16 '12 at 15:04
  • @user1315357: What do you mean by "correctly"? It's all a matter of what you want. But you should be able to get `PeriodFormat` to do what you want - you should construct the period to only use the units you want. It's hard to say what you're doing wrong without seeing your attempted code. – Jon Skeet Apr 16 '12 at 16:01
1

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()));
Jiri Patera
  • 3,032
  • 1
  • 18
  • 14
0

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"
user799188
  • 12,159
  • 3
  • 30
  • 35
0

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(); 
 }
Community
  • 1
  • 1
Smig
  • 663
  • 6
  • 16
0

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);
}
Community
  • 1
  • 1
notes-jj
  • 1,072
  • 13
  • 28