23

I'd like to format a Period using a pattern like YY years, MM months, DD days. The utilities in Java 8 are designed to format time but neither period, nor duration. There's a PeriodFormatter in Joda time. Does Java have similar utilities?

Mikhail Kholodkov
  • 23,642
  • 17
  • 61
  • 78
naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259

4 Answers4

16

One solution is to simply use String.format:

import java.time.Period;

Period p = Period.of(2,5,1);
String.format("%d years, %d months, %d days", p.getYears(), p.getMonths(), p.getDays());

If your really need to use the features of DateTimeFormatter, you can use a temporary LocalDate, but this is a kind of hack that distort the semantic of LocalDate.

import java.time.Period;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

Period p = Period.of(2,5,1);
DateTimeFormatter fomatter = DateTimeFormatter.ofPattern("y 'years,' M 'months,' d 'days'");
LocalDate.of(p.getYears(), p.getMonths(), p.getDays()).format(fomatter);
Ortomala Lokni
  • 56,620
  • 24
  • 188
  • 240
  • 2
    I don’t like seeing `LocalDate` used as a hack. Why not do the same placeholder with value replacement approach using the String facilities in Java? – Basil Bourque Dec 12 '18 at 21:38
  • 2
    I agree that distorting the semantic of `LocalDate` is not elegant and could lead to problems. – Ortomala Lokni Dec 12 '18 at 21:49
  • @BasilBourque I agree in general, but it seems to me that it's a workaround for a weakness in the JDK Api, which should allow the `DateTimeFormatter` to accept any `TemporalAmount`. – daniu Dec 15 '18 at 08:10
  • 1
    The problem with this (that Joda solves) is that your string is not localized. – DavidW Dec 20 '18 at 14:19
4

There's no need to use String.format() for simple string formatting. Using plain old string concatenation will be optimized by JVM:

Function<Period, String> format = p -> p.getYears() + " years, " + p.getMonths() + " months, " + p.getDays() + " days";
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
2
public static final String format(Period period){
    if (period == Period.ZERO) {
        return "0 days";
    } else {
        StringBuilder buf = new StringBuilder();
        if (period.getYears() != 0) {
            buf.append(period.getYears()).append(" years");
            if(period.getMonths()!= 0 || period.getDays() != 0) {
                buf.append(", ");
            }
        }

        if (period.getMonths() != 0) {
            buf.append(period.getMonths()).append(" months");
            if(period.getDays()!= 0) {
                buf.append(", ");
            }
        }

        if (period.getDays() != 0) {
            buf.append(period.getDays()).append(" days");
        }
        return buf.toString();
    }
}
Luk
  • 2,186
  • 2
  • 11
  • 32
-1

the proper way seems to be an intermediate LocalDate object and then calling format

date1.format(DateTimeFormatter.ofPattern("uuuu MM LLLL ee ccc"));
OR (where appropriate)
date1.format(DateTimeFormatter.ofPattern("uuuu MM LLLL ee ccc", Locale.CHINA))

this prints 1997 01 一月 07 周六 in chinese, 1997 01 January 01 Sun in english and 1997 01 januari 07 zo in dutch.

check out https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html under "Patterns for Formatting and Parsing" for your desired formatting.