Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A new method to format only with provided formats. #269

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 73 additions & 14 deletions src/main/java/org/threeten/extra/AmountFormats.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,11 @@
import java.time.Period;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAmount;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.*;
import java.util.function.Function;
import java.util.function.IntPredicate;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
Expand Down Expand Up @@ -96,35 +92,35 @@ public final class AmountFormats {
/**
* The property file key for the word "year".
*/
private static final String WORDBASED_YEAR = "WordBased.year";
public static final String WORDBASED_YEAR = "WordBased.year";
/**
* The property file key for the word "month".
*/
private static final String WORDBASED_MONTH = "WordBased.month";
public static final String WORDBASED_MONTH = "WordBased.month";
/**
* The property file key for the word "week".
*/
private static final String WORDBASED_WEEK = "WordBased.week";
public static final String WORDBASED_WEEK = "WordBased.week";
/**
* The property file key for the word "day".
*/
private static final String WORDBASED_DAY = "WordBased.day";
public static final String WORDBASED_DAY = "WordBased.day";
/**
* The property file key for the word "hour".
*/
private static final String WORDBASED_HOUR = "WordBased.hour";
public static final String WORDBASED_HOUR = "WordBased.hour";
/**
* The property file key for the word "minute".
*/
private static final String WORDBASED_MINUTE = "WordBased.minute";
public static final String WORDBASED_MINUTE = "WordBased.minute";
/**
* The property file key for the word "second".
*/
private static final String WORDBASED_SECOND = "WordBased.second";
public static final String WORDBASED_SECOND = "WordBased.second";
/**
* The property file key for the word "millisecond".
*/
private static final String WORDBASED_MILLISECOND = "WordBased.millisecond";
public static final String WORDBASED_MILLISECOND = "WordBased.millisecond";
/**
* The predicate that matches 1 or -1.
*/
Expand Down Expand Up @@ -303,6 +299,69 @@ public static String wordBased(Period period, Duration duration, Locale locale)
return wb.format(values);
}

/**
* Formats a period and duration to a string in a localized word-based format using the provided list of formats.
* <p>
* This returns a word-based format for the period and duration and only includes the provided formats.
* The year and month are printed as supplied unless the signs differ, in which case they are normalized.
* The words are configured in a resource bundle text file -
* {@code org.threeten.extra.wordbased.properties} - with overrides per language.
*
* @param period the period to format
* @param duration the duration to format
* @param formats a list of formats to include in the result
* @param locale the locale to use
* @return the localized word-based format for the period and duration
*/
public static String wordBasedWithFormats(Period period, Duration duration, List<String> formats, Locale locale) {
Objects.requireNonNull(period, "period must not be null");
Objects.requireNonNull(duration, "duration must not be null");
Objects.requireNonNull(formats, "formats must not be null");
Objects.requireNonNull(locale, "locale must not be null");
ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME, locale);

WordBased wb = new WordBased(formats.stream().map(f -> UnitFormat.of(bundle, f)).toArray(UnitFormat[]::new), bundle.getString(WORDBASED_COMMASPACE), bundle.getString(WORDBASED_SPACEANDSPACE));

Period normPeriod = oppositeSigns(period.getMonths(), period.getYears()) ? period.normalized() : period;
int weeks = 0;
int days = 0;
if (normPeriod.getDays() % DAYS_PER_WEEK == 0) {
weeks = normPeriod.getDays() / DAYS_PER_WEEK;
} else {
days = normPeriod.getDays();
}
long totalHours = duration.toHours();
days += (int) (totalHours / HOURS_PER_DAY);

List<Integer> values = new ArrayList<>();
if (formats.contains(WORDBASED_YEAR)) {
values.add(normPeriod.getYears());
}
if (formats.contains(WORDBASED_MONTH)) {
values.add(normPeriod.getMonths());
}
if (formats.contains(WORDBASED_WEEK)) {
values.add(weeks);
}
if (formats.contains(WORDBASED_DAY)) {
values.add(days);
}
if (formats.contains(WORDBASED_HOUR)) {
values.add((int) (totalHours % HOURS_PER_DAY));
}
if (formats.contains(WORDBASED_MINUTE)) {
values.add((int) (duration.toMinutes() % MINUTES_PER_HOUR));
}
if (formats.contains(WORDBASED_SECOND)) {
values.add((int) (duration.getSeconds() % SECONDS_PER_MINUTE));
}
if (formats.contains(WORDBASED_MILLISECOND)) {
values.add(duration.getNano() / NANOS_PER_MILLIS);
}

return wb.format(values.stream().mapToInt(Integer::intValue).toArray());
}

// are the signs opposite
private static boolean oppositeSigns(int a, int b) {
return a < 0 ? (b >= 0) : (b < 0);
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/org/threeten/extra/TestAmountFormats.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import java.time.Duration;
import java.time.Period;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -157,12 +159,38 @@ public static Object[][] period_duration_wordBased() {
};
}

public static Object[][] period_duration_wordBasedWithFormats() {
return new Object[][] {
{Period.ofDays(1), Duration.ofMinutes(180 + 2), Arrays.asList(AmountFormats.WORDBASED_DAY, AmountFormats.WORDBASED_HOUR), Locale.ROOT, "1 day and 3 hours"},
{Period.ofDays(2), Duration.ofSeconds(180), Arrays.asList(AmountFormats.WORDBASED_DAY, AmountFormats.WORDBASED_MINUTE), Locale.ROOT, "2 days and 3 minutes"},
{Period.ofDays(7), Duration.ofMinutes(80), Arrays.asList(AmountFormats.WORDBASED_WEEK, AmountFormats.WORDBASED_MINUTE), Locale.ROOT, "1 week and 20 minutes"},
{Period.ZERO, Duration.ofMillis(1_000), Arrays.asList(AmountFormats.WORDBASED_SECOND), Locale.ROOT, "1 second"},

{Period.ofMonths(0), Duration.ofSeconds(0), Arrays.asList(AmountFormats.WORDBASED_MILLISECOND), Locale.ENGLISH, "0 milliseconds"},
{Period.ofMonths(0), Duration.ofHours(9), Arrays.asList(AmountFormats.WORDBASED_HOUR), Locale.ENGLISH, "9 hours"},
{Period.ofMonths(1), Duration.ZERO, Arrays.asList(AmountFormats.WORDBASED_MONTH), Locale.ENGLISH, "1 month"},
{Period.ofMonths(4), Duration.ZERO, Arrays.asList(AmountFormats.WORDBASED_MONTH), Locale.ENGLISH, "4 months"},
{Period.of(1, 2, 5), Duration.ofHours(4),Arrays.asList(AmountFormats.WORDBASED_YEAR, AmountFormats.WORDBASED_MONTH, AmountFormats.WORDBASED_DAY, AmountFormats.WORDBASED_HOUR), Locale.ENGLISH, "1 year, 2 months, 5 days and 4 hours"},
{Period.ofDays(5), Duration.ofDays(2).plusHours(6), Arrays.asList(AmountFormats.WORDBASED_DAY, AmountFormats.WORDBASED_HOUR), Locale.ENGLISH, "7 days and 6 hours"},
{Period.ofDays(5), Duration.ofDays(-2).plusHours(-6), Arrays.asList(AmountFormats.WORDBASED_DAY, AmountFormats.WORDBASED_HOUR), Locale.ENGLISH, "3 days and -6 hours"},

{Period.ofDays(1), Duration.ofHours(5).plusMinutes(6).plusSeconds(7).plusNanos(8_000_000L), Arrays.asList(AmountFormats.WORDBASED_DAY, AmountFormats.WORDBASED_HOUR, AmountFormats.WORDBASED_MINUTE, AmountFormats.WORDBASED_SECOND, AmountFormats.WORDBASED_MILLISECOND), PL,
"1 dzie\u0144, 5 godzin, 6 minut, 7 sekund i 8 milisekund"},
};
}

@ParameterizedTest
@MethodSource("period_duration_wordBased")
public void test_wordBased(Period period, Duration duration, Locale locale, String expected) {
assertEquals(expected, AmountFormats.wordBased(period, duration, locale));
}

@ParameterizedTest
@MethodSource("period_duration_wordBasedWithFormats")
public void test_wordBasedWithFormats(Period period, Duration duration, List<String> formats, Locale locale, String expected) {
assertEquals(expected, AmountFormats.wordBasedWithFormats(period, duration, formats, locale));
}

//-----------------------------------------------------------------------
@Test
public void test_wordBased_pl_formatStandard() {
Expand Down