net.time4j.PrettyTime Maven / Gradle / Ivy
/*
* -----------------------------------------------------------------------
* Copyright © 2013-2015 Meno Hochschild,
* -----------------------------------------------------------------------
* This file (PrettyTime.java) is part of project Time4J.
*
* Time4J is free software: You can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Time4J is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Time4J. If not, see .
* -----------------------------------------------------------------------
*/
package net.time4j;
import net.time4j.base.MathUtils;
import net.time4j.base.ResourceLoader;
import net.time4j.base.TimeSource;
import net.time4j.base.UnixTime;
import net.time4j.engine.TimeSpan;
import net.time4j.format.NumberSymbolProvider;
import net.time4j.format.NumberSystem;
import net.time4j.format.NumberType;
import net.time4j.format.PluralCategory;
import net.time4j.format.PluralRules;
import net.time4j.format.TemporalFormatter;
import net.time4j.format.TextWidth;
import net.time4j.tz.TZID;
import net.time4j.tz.Timezone;
import net.time4j.tz.ZonalOffset;
import java.text.MessageFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAmount;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import static net.time4j.CalendarUnit.*;
import static net.time4j.ClockUnit.*;
/**
* Enables formatted output as usually used in social media in different
* languages.
*
* Parsing is not included because there is no general solution for all
* locales. Instead users must keep the backing duration object and use it
* for printing.
*
* @author Meno Hochschild
* @since 1.2
* @doctags.concurrency {immutable}
*/
/*[deutsch]
* Ermöglicht formatierte Ausgaben einer Dauer für soziale Medien
* ("social media style") in verschiedenen Sprachen.
*
* Der Rückweg der Interpretation (parsing) ist nicht enthalten,
* weil so nicht alle Sprachen unterstützt werden können. Stattdessen
* werden Anwender angehalten, das korrespondierende Dauer-Objekt im Hintergrund
* zu halten und es für die formatierte Ausgabe zu nutzen.
*
* @author Meno Hochschild
* @since 1.2
* @doctags.concurrency {immutable}
*/
public final class PrettyTime {
//~ Statische Felder/Initialisierungen --------------------------------
private static final NumberSymbolProvider NUMBER_SYMBOLS;
static {
NumberSymbolProvider p = null;
int count = 0;
for (NumberSymbolProvider tmp : ResourceLoader.getInstance().services(NumberSymbolProvider.class)) {
int size = tmp.getAvailableLocales().length;
if (size >= count) { // includes SymbolProviderSPI if available
p = tmp;
count = size;
}
}
if (p == null) {
p = NumberSymbolProvider.DEFAULT;
}
NUMBER_SYMBOLS = p;
}
private static final int MIO = 1000000;
private static final ConcurrentMap LANGUAGE_MAP = new ConcurrentHashMap<>();
private static final IsoUnit[] STD_UNITS;
private static final IsoUnit[] TSP_UNITS;
private static final Set SUPPORTED_UNITS;
private static final long START_1972;
static {
IsoUnit[] stdUnits = {YEARS, MONTHS, WEEKS, DAYS, HOURS, MINUTES, SECONDS};
STD_UNITS = stdUnits;
TSP_UNITS = new IsoUnit[]{YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS};
Set tmp = new HashSet<>();
Collections.addAll(tmp, stdUnits);
tmp.add(NANOS);
SUPPORTED_UNITS = Collections.unmodifiableSet(tmp);
START_1972 = 2 * 365 * 86400L;
}
//~ Instanzvariablen --------------------------------------------------
private final PluralRules rules;
private final Locale locale;
private final TimeSource> refClock;
private final char zeroDigit;
private final String minusSign;
private final IsoUnit emptyUnit;
private final boolean weekToDays;
private final boolean shortStyle;
//~ Konstruktoren -----------------------------------------------------
private PrettyTime(
Locale loc,
TimeSource> refClock,
char zeroDigit,
String minusSign,
IsoUnit emptyUnit,
boolean weekToDays,
boolean shortStyle
) {
super();
if (emptyUnit == null) {
throw new NullPointerException("Missing zero time unit.");
} else if (refClock == null) {
throw new NullPointerException("Missing reference clock.");
}
// throws NPE if language == null
this.rules = PluralRules.of(loc, NumberType.CARDINALS);
this.locale = loc;
this.refClock = refClock;
this.zeroDigit = zeroDigit;
this.emptyUnit = emptyUnit;
this.minusSign = minusSign;
this.weekToDays = weekToDays;
this.shortStyle = shortStyle;
}
//~ Methoden ----------------------------------------------------------
/**
* Gets an instance of {@code PrettyTime} for given language,
* possibly cached.
*
* @param locale the language an instance is searched for
* @return pretty time object for formatting durations or relative time
* @since 1.2
*/
/*[deutsch]
* Liefert eine Instanz von {@code PrettyTime} für die angegebene
* Sprache, eventuell aus dem Cache.
*
* @param locale the language an instance is searched for
* @return pretty time object for formatting durations or relative time
* @since 1.2
*/
public static PrettyTime of(Locale locale) {
PrettyTime ptime = LANGUAGE_MAP.get(locale);
if (ptime == null) {
ptime =
new PrettyTime(
locale,
SystemClock.INSTANCE,
NUMBER_SYMBOLS.getZeroDigit(locale),
NUMBER_SYMBOLS.getMinusSign(locale),
SECONDS,
false,
false);
PrettyTime old = LANGUAGE_MAP.putIfAbsent(locale, ptime);
if (old != null) {
ptime = old;
}
}
return ptime;
}
/**
* Gets the language of this instance.
*
* @return language
* @since 1.2
*/
/*[deutsch]
* Liefert die Bezugssprache.
*
* @return Spracheinstellung
* @since 1.2
*/
public Locale getLocale() {
return this.locale;
}
/**
* Yields the reference clock for formatting of relative times.
*
* @return reference clock or system clock if not yet specified
* @since 1.2
* @see #withReferenceClock(TimeSource)
* @see #printRelative(UnixTime, TZID)
* @see #printRelative(UnixTime, String)
*/
/*[deutsch]
* Liefert die Bezugsuhr für formatierte Ausgaben der relativen
* Zeit.
*
* @return Zeitquelle oder die Systemuhr, wenn noch nicht angegeben
* @since 1.2
* @see #withReferenceClock(TimeSource)
* @see #printRelative(UnixTime, TZID)
* @see #printRelative(UnixTime, String)
*/
public TimeSource> getReferenceClock() {
return this.refClock;
}
/**
* Yields a changed copy of this instance with given reference
* clock.
*
* @param clock new reference clock
* @return new instance of {@code PrettyTime} with changed reference clock
* @since 1.2
* @see #getReferenceClock()
* @see #printRelative(UnixTime, TZID)
* @see #printRelative(UnixTime, String)
*/
/*[deutsch]
* Legt die Bezugszeit für relative Zeitangaben neu fest.
*
* @param clock new reference clock
* @return new instance of {@code PrettyTime} with changed reference clock
* @since 1.2
* @see #getReferenceClock()
* @see #printRelative(UnixTime, TZID)
* @see #printRelative(UnixTime, String)
*/
public PrettyTime withReferenceClock(TimeSource> clock) {
return new PrettyTime(
this.locale,
clock,
this.zeroDigit,
this.minusSign,
this.emptyUnit,
this.weekToDays,
this.shortStyle);
}
/**
* Defines the localized zero digit based on given decimal number system.
*
* @param numberSystem decimal number system
* @return changed copy of this instance
* @throws IllegalArgumentException if the number system is not decimal
* @see #withZeroDigit(char)
* @since 3.24/4.20
*/
/*[deutsch]
* Definiert die lokalisierte Nullziffer, indem das angegebene Dezimalzahlsystem ausgewertet wird.
*
* @param numberSystem decimal number system
* @return changed copy of this instance
* @throws IllegalArgumentException if the number system is not decimal
* @see #withZeroDigit(char)
* @since 3.24/4.20
*/
public PrettyTime withZeroDigit(NumberSystem numberSystem) {
if (numberSystem.isDecimal()) {
return this.withZeroDigit(numberSystem.getDigits().charAt(0));
} else {
throw new IllegalArgumentException("Number system is not decimal: " + numberSystem);
}
}
/**
* Defines the localized zero digit.
*
* In most languages the zero digit is just ASCII-"0",
* but for example in arabic locales the digit can also be the char
* {@code U+0660}. By default Time4J will try to use the configuration
* of the module i18n or else the JDK-setting. This method can override
* it however.
*
* @param zeroDigit localized zero digit
* @return changed copy of this instance
* @since 1.2
* @see java.text.DecimalFormatSymbols#getZeroDigit()
* @see net.time4j.format.NumberSymbolProvider#getZeroDigit(Locale)
*/
/*[deutsch]
* Definiert die lokalisierte Nullziffer.
*
* In den meisten Sprachen ist die Nullziffer ASCII-"0",
* aber etwa im arabischen Sprachraum kann das Zeichen auch {@code U+0660}
* sein. Per Vorgabe wird Time4J versuchen, die Konfiguration des
* i18n-Moduls oder sonst die JDK-Einstellung zu verwenden. Diese
* Methode überschreibt jedoch den Standard.
*
* @param zeroDigit localized zero digit
* @return changed copy of this instance
* @since 1.2
* @see java.text.DecimalFormatSymbols#getZeroDigit()
* @see net.time4j.format.NumberSymbolProvider#getZeroDigit(Locale)
*/
public PrettyTime withZeroDigit(char zeroDigit) {
if (this.zeroDigit == zeroDigit) {
return this;
}
return new PrettyTime(
this.locale,
this.refClock,
zeroDigit,
this.minusSign,
this.emptyUnit,
this.weekToDays,
this.shortStyle);
}
/**
* Defines the localized minus sign.
*
* In most languages the minus sign is just {@code U+002D}. By default
* Time4J will try to use the configuration of the module i18n or else the
* JDK-setting. This method can override it however. Especially for arabic,
* it might make sense to first add a unicode marker (either LRM
* {@code U+200E} or RLM {@code U+200F}) in front of the minus sign
* in order to control the orientation in right-to-left-style.
*
* @param minusSign localized minus sign (possibly with unicode markers)
* @return changed copy of this instance
* @since 2.1
* @see java.text.DecimalFormatSymbols#getMinusSign()
* @see net.time4j.format.NumberSymbolProvider#getMinusSign(Locale)
*/
/*[deutsch]
* Definiert das lokalisierte Minuszeichen.
*
* In den meisten Sprachen ist es einfach das Zeichen {@code U+002D}.
* Per Vorgabe wird Time4J versuchen, die Konfiguration des
* i18n-Moduls oder sonst die JDK-Einstellung zu verwenden. Diese
* Methode überschreibt jedoch den Standard. Besonders für
* Arabisch kann es sinnvoll sein, vor dem eigentlichen Minuszeichen
* einen Unicode-Marker (entweder LRM {@code U+200E} oder RLM
* {@code U+200F}) einzufügen, um die Orientierung des Minuszeichens
* in der traditionellen Rechts-nach-links-Schreibweise zu
* kontrollieren.
*
* @param minusSign localized minus sign (possibly with unicode markers)
* @return changed copy of this instance
* @since 2.1
* @see java.text.DecimalFormatSymbols#getMinusSign()
* @see net.time4j.format.NumberSymbolProvider#getMinusSign(Locale)
*/
public PrettyTime withMinusSign(String minusSign) {
if (minusSign.equals(this.minusSign)) { // NPE-check
return this;
}
return new PrettyTime(
this.locale,
this.refClock,
this.zeroDigit,
minusSign,
this.emptyUnit,
this.weekToDays,
this.shortStyle);
}
/**
* Defines the time unit used for formatting an empty duration.
*
* Time4J uses seconds as default. This method can override the
* default however.
*
* @param emptyUnit time unit for usage in an empty duration
* @return changed copy of this instance
* @since 1.2
* @see #print(Duration, TextWidth)
*/
/*[deutsch]
* Definiert die Zeiteinheit für die Verwendung in der
* Formatierung einer leeren Dauer.
*
* Vorgabe ist die Sekundeneinheit. Diese Methode kann die Vorgabe
* jedoch überschreiben.
*
* @param emptyUnit time unit for usage in an empty duration
* @return changed copy of this instance
* @since 1.2
* @see #print(Duration, TextWidth)
*/
public PrettyTime withEmptyUnit(CalendarUnit emptyUnit) {
if (this.emptyUnit.equals(emptyUnit)) {
return this;
}
return new PrettyTime(
this.locale,
this.refClock,
this.zeroDigit,
this.minusSign,
emptyUnit,
this.weekToDays,
this.shortStyle);
}
/**
* Defines the time unit used for formatting an empty duration.
*
* Time4J uses seconds as default. This method can override the
* default however.
*
* @param emptyUnit time unit for usage in an empty duration
* @return changed copy of this instance
* @since 1.2
* @see #print(Duration, TextWidth)
*/
/*[deutsch]
* Definiert die Zeiteinheit für die Verwendung in der
* Formatierung einer leeren Dauer.
*
* Vorgabe ist die Sekundeneinheit. Diese Methode kann die Vorgabe
* jedoch überschreiben.
*
* @param emptyUnit time unit for usage in an empty duration
* @return changed copy of this instance
* @since 1.2
* @see #print(Duration, TextWidth)
*/
public PrettyTime withEmptyUnit(ClockUnit emptyUnit) {
if (this.emptyUnit.equals(emptyUnit)) {
return this;
}
return new PrettyTime(
this.locale,
this.refClock,
this.zeroDigit,
this.minusSign,
emptyUnit,
this.weekToDays,
this.shortStyle);
}
/**
* Determines that weeks will always be normalized to days.
*
* @return changed copy of this instance
* @since 2.0
*/
/*[deutsch]
* Legt fest, daß Wochen immer zu Tagen normalisiert werden.
*
* @return changed copy of this instance
* @since 2.0
*/
public PrettyTime withWeeksToDays() {
if (this.weekToDays) {
return this;
}
return new PrettyTime(
this.locale,
this.refClock,
this.zeroDigit,
this.minusSign,
this.emptyUnit,
true,
this.shortStyle);
}
/**
* Mandates the use of abbreviations as default style.
*
* All {@code print()}-methods with explicit {@code TextWidth}-parameters will ignore this
* setting however. This method is mainly relevant for printing relative times.
*
* @return changed copy of this instance
* @since 3.6/4.4
*/
/*[deutsch]
* Legt die Verwendung von Abkürzungen als Vorgabestil fest.
*
* Alle {@code print()}-Methoden mit einem expliziten {@code TextWidth}-Parameter ignorieren diese
* Einstellung. Diese Methode ist hauptsächlich für die Formatierung von relativen Zeitangaben
* von Bedeutung.
*
* @return changed copy of this instance
* @since 3.6/4.4
*/
public PrettyTime withShortStyle() {
if (this.shortStyle) {
return this;
}
return new PrettyTime(
this.locale,
this.refClock,
this.zeroDigit,
this.minusSign,
this.emptyUnit,
this.weekToDays,
true);
}
/**
* Determines the localized word for "today".
*
* @return String
* @since 3.24/4.20
*/
/*[deutsch]
* Ermittelt das lokalisierte Wort für "heute".
*
* @return String
* @since 3.24/4.20
*/
public String printToday() {
return UnitPatterns.of(this.getLocale()).getTodayWord();
}
/**
* Formats given duration in calendar units.
*
* Note: Millennia, centuries and decades are automatically normalized
* to years while quarter-years are normalized to months.
*
* @param amount count of units (quantity)
* @param unit calendar unit
* @param width text width (ABBREVIATED as synonym for SHORT)
* @return formatted output
* @since 1.2
* @see #print(Duration, TextWidth)
*/
/*[deutsch]
* Formatiert die angegebene Dauer in kalendarischen Zeiteinheiten.
*
* Hinweis: Jahrtausende, Jahrhunderte und Dekaden werden automatisch
* zu Jahren normalisiert, während Quartale zu Monaten normalisiert
* werden.
*
* @param amount Anzahl der Einheiten
* @param unit kalendarische Zeiteinheit
* @param width text width (ABBREVIATED as synonym for SHORT)
* @return formatierte Ausgabe
* @since 1.2
* @see #print(Duration, TextWidth)
*/
public String print(
long amount,
CalendarUnit unit,
TextWidth width
) {
UnitPatterns p = UnitPatterns.of(this.locale);
CalendarUnit u;
switch (unit) {
case MILLENNIA:
amount = MathUtils.safeMultiply(amount, 1000);
u = CalendarUnit.YEARS;
break;
case CENTURIES:
amount = MathUtils.safeMultiply(amount, 100);
u = CalendarUnit.YEARS;
break;
case DECADES:
amount = MathUtils.safeMultiply(amount, 10);
u = CalendarUnit.YEARS;
break;
case YEARS:
u = CalendarUnit.YEARS;
break;
case QUARTERS:
amount = MathUtils.safeMultiply(amount, 3);
u = CalendarUnit.MONTHS;
break;
case MONTHS:
u = CalendarUnit.MONTHS;
break;
case WEEKS:
if (this.weekToDays) {
amount = MathUtils.safeMultiply(amount, 7);
u = CalendarUnit.DAYS;
} else {
u = CalendarUnit.WEEKS;
}
break;
case DAYS:
u = CalendarUnit.DAYS;
break;
default:
throw new UnsupportedOperationException(unit.name());
}
String pattern = p.getPattern(width, this.getCategory(amount), u);
return this.format(pattern, amount);
}
/**
* Formats given duration in clock units.
*
* @param amount count of units (quantity)
* @param unit clock unit
* @param width text width (ABBREVIATED as synonym for SHORT)
* @return formatted output
* @since 1.2
* @see #print(Duration, TextWidth)
*/
/*[deutsch]
* Formatiert die angegebene Dauer in Uhrzeiteinheiten.
*
* @param amount Anzahl der Einheiten
* @param unit Uhrzeiteinheit
* @param width text width (ABBREVIATED as synonym for SHORT)
* @return formatierte Ausgabe
* @since 1.2
* @see #print(Duration, TextWidth)
*/
public String print(
long amount,
ClockUnit unit,
TextWidth width
) {
String pattern = UnitPatterns.of(this.locale).getPattern(width, this.getCategory(amount), unit);
return this.format(pattern, amount);
}
/**
* Formats the total given duration.
*
* A localized output is only supported for the units
* {@link CalendarUnit#YEARS}, {@link CalendarUnit#MONTHS},
* {@link CalendarUnit#WEEKS}, {@link CalendarUnit#DAYS} and
* all {@link ClockUnit}-units. This method performs an internal
* normalization if any other unit is involved.
*
* Note: This method uses full words by default. If
* {@link #withShortStyle()} is called then abbreviations will be used.
*
* @param duration object representing a duration which might contain several units and quantities
* @return formatted list output
* @since 3.6/4.4
*/
/*[deutsch]
* Formatiert die gesamte angegebene Dauer.
*
* Eine lokalisierte Ausgabe ist nur für die Zeiteinheiten
* {@link CalendarUnit#YEARS}, {@link CalendarUnit#MONTHS},
* {@link CalendarUnit#WEEKS}, {@link CalendarUnit#DAYS} und
* alle {@link ClockUnit}-Instanzen vorhanden. Bei Bedarf werden
* andere Einheiten zu diesen normalisiert.
*
* Hinweis: Diese Methode verwendet standardmäß volle
* Wörter. Falls {@link #withShortStyle()} aufgerufen wurde, werden
* Abkürzungen verwendet.
*
* @param duration object representing a duration which might contain several units and quantities
* @return formatted list output
* @since 3.6/4.4
*/
public String print(Duration> duration) {
TextWidth width = (this.shortStyle ? TextWidth.ABBREVIATED : TextWidth.WIDE);
return this.print(duration, width, false, Integer.MAX_VALUE);
}
/**
* Short-cut for {@code print(Duration.from(threeten))}.
*
* @param threeten object representing a duration which might contain several units and quantities
* @return formatted list output in normalized form
* @throws IllegalArgumentException in case of conversion failures
* @since 4.4
* @see #print(Duration)
*/
/*[deutsch]
* Abkürzung für {@code print(Duration.from(threeten))}.
*
* @param threeten object representing a duration which might contain several units and quantities
* @return formatted list output in normalized form
* @throws IllegalArgumentException in case of conversion failures
* @since 4.4
* @see #print(Duration)
*/
public String print(TemporalAmount threeten) {
return this.print(Duration.from(threeten));
}
/**
* Formats the total given duration.
*
* A localized output is only supported for the units
* {@link CalendarUnit#YEARS}, {@link CalendarUnit#MONTHS},
* {@link CalendarUnit#WEEKS}, {@link CalendarUnit#DAYS} and
* all {@link ClockUnit}-units. This method performs an internal
* normalization if any other unit is involved.
*
* @param duration object representing a duration which might contain
* several units and quantities
* @param width text width (ABBREVIATED as synonym for SHORT)
* @return formatted list output
* @since 1.2
*/
/*[deutsch]
* Formatiert die gesamte angegebene Dauer.
*
* Eine lokalisierte Ausgabe ist nur für die Zeiteinheiten
* {@link CalendarUnit#YEARS}, {@link CalendarUnit#MONTHS},
* {@link CalendarUnit#WEEKS}, {@link CalendarUnit#DAYS} und
* alle {@link ClockUnit}-Instanzen vorhanden. Bei Bedarf werden
* andere Einheiten zu diesen normalisiert.
*
* @param duration object representing a duration which might contain
* several units and quantities
* @param width text width (ABBREVIATED as synonym for SHORT)
* @return formatted list output
* @since 1.2
*/
public String print(
Duration> duration,
TextWidth width
) {
return this.print(duration, width, false, Integer.MAX_VALUE);
}
/**
* Short-cut for {@code print(Duration.from(threeten), width)}.
*
* @param threeten object representing a duration which might contain several units and quantities
* @param width text width (ABBREVIATED as synonym for SHORT)
* @return formatted list output in normalized form
* @throws IllegalArgumentException in case of conversion failures
* @since 4.0
* @see #print(Duration, TextWidth)
*/
/*[deutsch]
* Abkürzung für {@code print(Duration.from(threeten), width)}.
*
* @param threeten object representing a duration which might contain several units and quantities
* @param width text width (ABBREVIATED as synonym for SHORT)
* @return formatted list output in normalized form
* @throws IllegalArgumentException in case of conversion failures
* @since 4.0
* @see #print(Duration, TextWidth)
*/
public String print(
TemporalAmount threeten,
TextWidth width
) {
return this.print(Duration.from(threeten), width);
}
/**
* Formats given duration.
*
* Like {@link #print(Duration, TextWidth)}, but offers the
* option to limit the count of displayed duration items and also
* to print items with zero amount. The first printed duration item
* has always a non-zero amount however. Example:
*
*
* Duration<?> dur =
* Duration.ofZero().plus(1, DAYS).plus(4, ClockUnit.MINUTES);
* System.out.println(
* PrettyTime.of(Locale.FRANCE).print(dur, TextWidth.WIDE, true, 3));
* // output: 1 jour, 0 heure et 4 minutes
*
*
* @param duration object representing a duration which might contain
* several units and quantities
* @param width text width (ABBREVIATED as synonym for SHORT)
* @param printZero determines if zero amounts shall be printed, too
* @param maxLength maximum count of displayed items
* @return formatted list output
* @throws IllegalArgumentException if maxLength is smaller than {@code 1}
* @since 2.0
*/
/*[deutsch]
* Formatiert die angegebene Dauer.
*
* Wie {@link #print(Duration, TextWidth)}, aber mit der Option, die
* Anzahl der Dauerelemente zu begrenzen und auch Elemente mit dem
* Betrag {@code 0} auszugeben. Das erste ausgegebene Element hat aber
* immer einen Betrag ungleich {@code 0}. Beispiel:
*
*
* Duration<?> dur =
* Duration.ofZero().plus(1, DAYS).plus(4, ClockUnit.MINUTES);
* System.out.println(
* PrettyTime.of(Locale.FRANCE).print(dur, TextWidth.WIDE, true, 3));
* // output: 1 jour, 0 heure et 4 minutes
*
*
* @param duration object representing a duration which might contain
* several units and quantities
* @param width text width (ABBREVIATED as synonym for SHORT)
* @param printZero determines if zero amounts shall be printed, too
* @param maxLength maximum count of displayed items
* @return formatted list output
* @throws IllegalArgumentException if maxLength is smaller than {@code 1}
* @since 2.0
*/
public String print(
Duration> duration,
TextWidth width,
boolean printZero,
int maxLength
) {
if (maxLength < 1) {
throw new IllegalArgumentException(
"Max length is invalid: " + maxLength);
}
// special case of empty duration
if (duration.isEmpty()) {
if (this.emptyUnit.isCalendrical()) {
CalendarUnit unit = CalendarUnit.class.cast(this.emptyUnit);
return this.print(0, unit, width);
} else {
ClockUnit unit = ClockUnit.class.cast(this.emptyUnit);
return this.print(0, unit, width);
}
}
// fill values-array from duration
boolean negative = duration.isNegative();
long[] values = new long[8];
pushDuration(values, duration, this.refClock, this.weekToDays);
// format duration items
List