Reputation: 616
I'd like to print durations given in milliseconds with different format specification depending on its size:
case (1) "H:mm" if duration < 10 hours
case (2) "HH:mm" if duration < 24 hours
case (3) "#d HH:mm" else (duration >= 24 hours)
which means only 1 hour field digit for durations lower than 10 hours,
but 2 hour field digits when having a leading day field!
Examples:
case (1) "0:45" means 45 minutes,
"1:23" means 1 hour and 23 minutes,
case (2) "12:05" means 12 hours and 5 minutes and
case (3) "1d 05:09" means 1 day, 5 hours and 9 minutes
(= 29 hours and 9 minutes).
I had tried with
object JodaTest {
import org.joda.time._
private val pdf = {
import format._
val pfb = new PeriodFormatterBuilder()
.appendDays.appendSeparator("d ")
.printZeroAlways
.minimumPrintedDigits(2).appendHours.appendSeparator(":")
.appendMinutes
new PeriodFormatter(pfb.toPrinter, null)
}
def durstr(duration: Long): String =
pdf.print((new Period(duration)).normalizedStandard)
}
which leads to
2700000 => "00:45" but should be "0:45"
4980000 => "01:23" but should be "1:23"
43500000 => "12:05"
104940000 => "1d 05:09"
but I don't know how to omit leading zero of two-digit-day-representation in case (1) but simultaneously force to print it in case (3) with same PeriodFormat.
Is it possible to do that with a single org.joda.time.format.PeriodFormatter
?
Upvotes: 5
Views: 3948
Reputation: 63385
You can implement the PeriodPrinter
interface to format the period exactly as you want, then use the builder to set up the formatter.
Upvotes: 0
Reputation: 616
Still found a solution with only one PeriodFormatter
but doing a little work outside Joda-Time.
The idea is to
with
object JodaTest {
import org.joda.time._
import format._
// "000d 00:00" - 3 day digits for periods with up to 999 days long
private val pdf = new PeriodFormatter(new PeriodFormatterBuilder()
.printZeroAlways
.minimumPrintedDigits(3).appendDays.appendSeparator("d ")
.minimumPrintedDigits(2).appendHours.appendSeparator(":").appendMinutes
.toPrinter, null)
private def adjust(rawstr: String): String = {
// "000d 00:00" => ("000d 0", "0:00")
val (first, second) = rawstr splitAt 6
// remove unwanted leading zeros in first part, keep it in second
first.dropWhile(c => !c.isDigit || c == '0') + second
}
def durstr(duration: Long): String = {
// PeriodType.dayTime => day is the most significant field (no weeks etc.)
adjust(pdf.print(new Period(duration) normalizedStandard PeriodType.dayTime))
}
}
which leads to
duration => rawstr => adjust
0 => "000d 00:00" => "0:00"
2700000 => "000d 00:45" => "0:45"
4980000 => "000d 01:23" => "1:23"
43500000 => "000d 12:05" => "12:05"
104940000 => "001d 05:09" => "1d 05:09"
518760000 => "006d 00:06" => "6d 00:06"
605220000 => "007d 00:07" => "7d 00:07"
951060000 => "011d 00:11" => "11d 00:11"
43230000000 => "500d 08:20" => "500d 08:20"
Of course, it would be nice to build such formats directly with Joda-Time by specifying a pattern like an Excel number format (#,##0.00#) to say where one want zeros ever or only if required. But it seems not clear how to define it exactly because you have not only '0' and '#' but need chars for each field and put literals into format string (perhaps via escaping) would be nice too.
Upvotes: 0
Reputation: 616
Perhaps not a real answer but meanwhile I'm afraid that you need two PeriodFormatter
to solve this task, so manage it with
object JodaTest {
import org.joda.time._
import format._
private def pdf(digits: Int) = new PeriodFormatter(
new PeriodFormatterBuilder()
.appendDays.appendSeparator("d ")
.printZeroAlways
.minimumPrintedDigits(digits).appendHours.appendSeparator(":")
.minimumPrintedDigits(2).appendMinutes
.toPrinter, null)
private lazy val pdf1 = pdf(1)
private lazy val pdf2 = pdf(2)
def durstr(duration: Long): String = {
val period = new Period(duration).normalizedStandard
val pdf = if (period.getDays > 0) pdf2 else pdf1
pdf.print(period)
}
}
which leads to desired
2700000 => "0:45"
4980000 => "1:23"
43500000 => "12:05"
104940000 => "1d 05:09".
Upvotes: 1