public final class FormattingDocumentation extends Object
Do not use SimpleDateFormat
, it does not work with all temporal data types of the SDK:
final LocalDate localDate = LocalDate.now();
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yy");
assertThatThrownBy(() -> simpleDateFormat.format(localDate))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Cannot format given Object as a Date");
See the test code.
LocalDate.format(DateTimeFormatter)
with DateTimeFormatter
instead:
final LocalDate localDate = LocalDate.of(2015, 7, 25);
assertThat(localDate.format(DateTimeFormatter.ofPattern("dd.MM.yy"))).isEqualTo("25.07.15");
assertThat(localDate.format(DateTimeFormatter.ISO_LOCAL_DATE)).isEqualTo("2015-07-25");
assertThat(localDate.format(
DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.GERMANY)
)).isEqualTo("25.07.2015");
assertThat(localDate.format(
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(Locale.GERMANY)
)).isEqualTo("Samstag, 25. Juli 2015");
See the test code.
final LocalTime localTime = LocalTime.of(16, 35);
assertThat(localTime.format(DateTimeFormatter.ofPattern("HH:mm"))).isEqualTo("16:35");
assertThat(localTime.format(DateTimeFormatter.ISO_LOCAL_TIME)).isEqualTo("16:35:00");
assertThat(localTime.format(
DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM).withLocale(Locale.GERMANY)
)).isEqualTo("16:35:00");
See the test code.
final String timeAsString = "2015-07-09T07:46:40.230Z";//typical date format from the API
final ZonedDateTime dateTime = ZonedDateTime.parse(timeAsString);
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
assertThat(dateTime.format(formatter)).isEqualTo("09.07.2015 07:46");
assertThat(dateTime.withZoneSameInstant(ZoneOffset.UTC).format(formatter))
.overridingErrorMessage("Timezone is UTC, so without transforming the value into the right timezone, " +
"the displayed date is not accurate")
.isEqualTo("09.07.2015 07:46");
assertThat(dateTime.withZoneSameInstant(ZoneId.of("Europe/Berlin")).format(formatter))
.isEqualTo("09.07.2015 09:46");
assertThat(dateTime.withZoneSameInstant(ZoneId.of("Europe/London")).format(formatter))
.isEqualTo("09.07.2015 08:46");
assertThat(dateTime.withZoneSameInstant(ZoneId.of("America/New_York")).format(formatter))
.isEqualTo("09.07.2015 03:46");
assertThat(dateTime.withZoneSameInstant(ZoneId.of("America/Los_Angeles")).format(formatter))
.isEqualTo("09.07.2015 00:46");
assertThat(dateTime.withZoneSameInstant(ZoneId.of("Europe/Berlin")).format(
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(Locale.GERMANY)
)).isEqualTo("Donnerstag, 9. Juli 2015");
See the test code.
final List<MonetaryAmount> monetaryAmounts = asList(
MoneyImpl.of(new BigDecimal("1234.56"), Monetary.getCurrency("EUR")),
MoneyImpl.of(new BigDecimal("1234.56"), DefaultCurrencyUnits.EUR),
MoneyImpl.of("1234.56", "EUR"),
MoneyImpl.ofCents(123456, Monetary.getCurrency("EUR")),
MoneyImpl.ofCents(123456, Monetary.getCurrency(Locale.GERMANY)),//auto select per county
MoneyImpl.ofCents(123456, DefaultCurrencyUnits.EUR),
MoneyImpl.ofCents(123456, "EUR")
);
monetaryAmounts.forEach(monetaryAmount -> {
assertThat(monetaryAmount.getCurrency()).isEqualTo(DefaultCurrencyUnits.EUR);
final long centAmount = monetaryAmount.scaleByPowerOfTen(2).getNumber().longValue();
assertThat(centAmount).isEqualTo(123456L);
});
See the test code.
For formatting you can just get a formatter per locale.
Example for Germany:
final MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.GERMANY);
assertThat(format.format(MoneyImpl.ofCents(123456, "EUR"))).isEqualTo("1.234,56 EUR");
See the test code.
Example for the USA:
final MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.US);
assertThat(format.format(MoneyImpl.ofCents(123456, "USD"))).isEqualTo("USD1,234.56");
See the test code.
You can also use the locale and force to use the currency symbol instead of the currency code:
final MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(
AmountFormatQueryBuilder.of(Locale.US)
.set(CurrencyStyle.SYMBOL)
.build()
);
final String formatted = format.format(MoneyImpl.ofCents(123456, "USD"));
assertThat(formatted).isEqualTo("$1,234.56");
See the test code.
If that is not flexible enough you can specify a pattern:
final MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(
AmountFormatQueryBuilder.of(Locale.US)
.set(CurrencyStyle.SYMBOL)
.set("pattern", "###0.00### ¤")
.build()
);
final String formatted = format.format(MoneyImpl.ofCents(123456, "USD"));
assertThat(formatted).isEqualTo("1234.56 $");
See the test code.
¤ is the currency sign which can be formatted with the styles CurrencyStyle.CODE
, CurrencyStyle.NAME
, CurrencyStyle.NUMERIC_CODE
and CurrencyStyle.SYMBOL
.
Be aware of that there is a difference if you use a locale with a language or a locale with both language and country:
final Locale germany = Locale.GERMANY;
assertThat(germany.toLanguageTag()).as("contains language and country").isEqualTo("de-DE");
final Locale german = Locale.GERMAN;
assertThat(german.toLanguageTag()).as("contains language").isEqualTo("de");
final MonetaryAmount amount = MoneyImpl.ofCents(123456, "EUR");
final MonetaryAmountFormat formatByLanguageAndCountry = MonetaryFormats.getAmountFormat(
AmountFormatQueryBuilder.of(germany)
.set(CurrencyStyle.SYMBOL)
.build()
);
final MonetaryAmountFormat formatByJustLanguage = MonetaryFormats.getAmountFormat(
AmountFormatQueryBuilder.of(german)
.set(CurrencyStyle.SYMBOL)
.build()
);
assertThat(formatByLanguageAndCountry.format(amount)).as("contains symbol").isEqualTo("1.234,56 €");
assertThat(formatByJustLanguage.format(amount)).as("contains not symbol").isEqualTo("EUR 1.234,56");
See the test code.
MonetaryQueries.convertMinorPart()
to get the whole amount as cents:
final MonetaryAmount amount = MoneyImpl.of(new BigDecimal("1234.56"), "EUR");
final Long centAmount = amount.query(MonetaryQueries.convertMinorPart());
assertThat(centAmount).isEqualTo(123456);
See the test code.
MonetaryQueries.extractMinorPart()
to get the minor unit (cent) part:
final MonetaryAmount amount = MoneyImpl.of(new BigDecimal("1234.56"), "EUR");
final Long centPart = amount.with(MonetaryOperators.minorPart()).query(MonetaryQueries.extractMinorPart());
assertThat(centPart).isEqualTo(56);
See the test code.
MonetaryQueries.extractMajorPart()
to get the smooth amount:
final MonetaryAmount amount = MoneyImpl.of(new BigDecimal("1234.56"), "EUR");
final Long centAmount = amount.query(MonetaryQueries.extractMajorPart());
assertThat(centAmount).isEqualTo(1234);
See the test code.
By the amount:
final MonetaryAmount a = MoneyImpl.ofCents(-200, "EUR");
final MonetaryAmount b = MoneyImpl.ofCents(100, "EUR");
final MonetaryAmount c = MoneyImpl.ofCents(5000, "EUR");
final List<MonetaryAmount> monetaryAmounts = asList(c, a, b);
final Comparator<MonetaryAmount> comparator = MonetaryFunctions.sortNumber();//useful for all the same currency
final List<MonetaryAmount> sorted = monetaryAmounts.stream().sorted(comparator).collect(toList());
assertThat(sorted).containsExactly(a, b, c);
See the test code.
By the currency and the amount:
final MonetaryAmount a = MoneyImpl.ofCents(-200, "EUR");
final MonetaryAmount b = MoneyImpl.ofCents(100, "EUR");
final MonetaryAmount c = MoneyImpl.ofCents(5000, "EUR");
final MonetaryAmount d = MoneyImpl.ofCents(100, "USD");
final MonetaryAmount e = MoneyImpl.ofCents(5000, "USD");
final List<MonetaryAmount> monetaryAmounts = asList(c, d, a, e, b);
final Comparator<MonetaryAmount> comparator =
MonetaryFunctions.sortCurrencyUnit().thenComparing(MonetaryFunctions.sortNumber());
final List<MonetaryAmount> sorted = monetaryAmounts.stream().sorted(comparator).collect(toList());
assertThat(sorted).isEqualTo(asList(a, b, c, d, e));
See the test code.
See JavaMoney Moneta User Guide - Rounding.
final MonetaryAmount amount = MoneyImpl.of(new BigDecimal("13.3750"), "EUR");
final MonetaryAmount rounded = amount.with(Monetary.getDefaultRounding());
assertThat(rounded).isEqualTo(MoneyImpl.of(new BigDecimal("13.38"), "EUR"));
See the test code.
final MonetaryAmount amount = MoneyImpl.of(new BigDecimal("13.3749"), "EUR");
final MonetaryAmount rounded = amount.with(Monetary.getDefaultRounding());
assertThat(rounded).isEqualTo(MoneyImpl.of(new BigDecimal("13.37"), "EUR"));
See the test code.