Reputation: 36203
I'm using
MessageFormat.format("Hello {0}", "World"));
Now I want to use LocalDate
or LocalDateTime
as parameters but as far as I can see MessageFormat.format
doesn't support java.time
!
So I have to use
MessageFormat.format("Today is {0,date}",
Date.from(LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
This is terrible!
Is there a better way to use MessageFormat
with java.time
? Or are there better solutions to replace placeholders in a text that considers Locale configuration?
Update
I'm aware of how to format LocalDate and LocalDateTime but I have the requirement to format a message with various types.
Example
MessageFormat.format("Today is {0,date} {1,number} {2}", aDate, aNumber, aString);
Where is the replacement for MessageFormat
with java.time
Types?
Upvotes: 9
Views: 2680
Reputation: 4233
Java 23 added support for java.time objects in MessageFormat. See Java 23 MessageFormat Javadoc.
Examples:
System.out.println(MessageFormat.format("LocalDateTime: {0,dtf_datetime}", LocalDateTime.now()));
// Jan 25, 2025, 9:12:48 PM
System.out.println(MessageFormat.format("LocalTime with style: {0,dtf_time,short}", LocalTime.now()));
// 9:12 PM
System.out.println(MessageFormat.format("LocalDate with custom format: {0,dtf_date,GGGG yyyy MMMM dd}", LocalDate.now()));
// Anno Domini 2025 January 25
System.out.println(MessageFormat.format("LocalDate with pre-defined formatter: {0,ISO_WEEK_DATE}", LocalDate.now()));
// 2025-W04-6
Upvotes: 1
Reputation: 740
MessageFormat allows to create and set up a custom format for any argument.
val randomDate = LocalDate.EPOCH.plusDays(random.nextInt(20_000));
val fmt = new MessageFormat("Today is {0}");
fmt.setFormat(0, new SummaryDateFormat());
val out = fmt.format(new Object[]{randomDate});
System.out.println(out);
Here is a sample implementation of your custom format:
public class SummaryDateFormat extends Format {
@Override
public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
toAppendTo.append(String.format("%tA, %<tB %<te", obj));
return toAppendTo;
}
@Override
public Object parseObject(final String source, final ParsePosition pos) {
return null;
}
}
Upvotes: 4
Reputation: 36203
I finally found a bug report about supporting java.time
in MessageFormat
.
https://bugs.openjdk.java.net/browse/JDK-8254654
Until this is solved I will go with the suggested workaround and convert LocalDate
etc. to java.util.Date
Upvotes: 3
Reputation: 272760
There had been an issue opened for this, which was resolved as "won't fix". The reason is that:
The
MessageFormat
is designed to work withjava.text.Format
classes, so it usesDateFormat
/SimpleDateFormat
to format date/time. Providing support forjava.time.format.DateTimeFormatter
to formatjava.time
types (TemporalAccessors
) may complicate theMessageFormat
API. It is always recommended to usejava.util.Formatter
which provides support for formattingjava.time
types.
So you should use Formatter
instead:
StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter(sb, Locale.US);
int someNumber = 10;
String someString = "Hello";
formatter.format("Today is %tD and someNumber is %d %s", LocalDate.now(), someNumber, someString);
System.out.println(sb);
// prints "Today is 03/30/21 and someNumber is 10 Hello"
This works with any kind of TemporalAccessor
.
Upvotes: 11