tags:

views:

232

answers:

3

I'm implementing a count-down using Joda Time. I only need a display accuracy of seconds.

However when printing the time, the seconds are displayed as full seconds, so when the count down reaches, for example, 900ms, then "0" seconds is printed, but as a count-down it would make more sense to display "1" second, until the time actually reaches 0ms.

Example:

void printDuration(Duration d) {
  System.out.println(
    d.toPeriod(PeriodType.time()).toString(
      new PeriodFormatterBuilder().printZeroAlways().appendSeconds().toFormatter()
    )
  );
}

printDuration(new Duration(5000)); // Prints "5" => OK
printDuration(new Duration(4900)); // Prints "4" => need "5"
printDuration(new Duration(1000)); // Prints "1" => OK
printDuration(new Duration(900));  // Prints "0" => need "1"
printDuration(new Duration(0));    // Prints "0" => OK

Basically I need to the seconds to be display rounded up from milliseconds and not rounded down. Is there a way to achieve this with Joda without needing to write my own formatter?

+1  A: 

The simplest way would be to take the existing duration, round the milliseconds appropriately to create a new duration, and format that:

private static Duration roundToSeconds(Duration d) {
  return new Duration(((d.getMillis() + 500) / 1000) * 1000);
}

(Note that this assumes positive durations, otherwise the rounding will be odd.)

Jon Skeet
Since I always want to round up, I guess I'd need to add 999 not 500. This would work as a work-around, but there should be a better solution.
RoToRa
@RoToRa: You *always* want to round up? So 1ms should be shown as "1"? That's somewhat unusual - but it would suggest adding 999, yes.
Jon Skeet
Yes, always. It's a count down, so I don't want to display "0" until the time is actually over and 1ms isn't over :-)
RoToRa
A: 

Are you interested in printing only durations of a few seconds ?

If not, your printDuration method is wrong (it prints 0 for Duration(60000) - ie, prints only the seconds fractions)

(BTW, it makes me uncofortable to see that formatter instantiated in each call)

If yes, (or if you are satisfied with printing "3600" for a Duration of one hour) you actually don't need time intelligence, it would be more simple to do the formatting yourself:

static void printDuration(Duration d) {
      int secs = (int)((d.getMillis()+999)/1000); 
      System.out.println(secs);
}

As Jon points out, this only makes sense for positive durations.

leonbloy
The real printDuration will also show hours and minutes, too. The example was simplyfied to display the problem.
RoToRa
A: 
import java.math.BigDecimal;

private Duration round(Duration d) {
  return Duration.standardSeconds(new BigDecimal(d.getMillis()).divide(1000, 0, BigDecimal.ROUND_up));
}

and then:

void printDuration(Duration d) {
    System.out.println(
        round(d).toPeriod(PeriodType.time()).toString(
            new PeriodFormatterBuilder().printZeroAlways().appendSeconds().toFormatter()
        )
    );
}
Jonas Fagundes