Reputation: 33
I want to format a date, which should be localized and includes the "day period".
"Day period" meaning not am/pm but "afternoon", "early morning" etc.
A formatted date based on german locale with the 12 hour setting enabled should look like 03.08.18, 9:01 abends
, "abends" meaning evening.
The same example should be 3/8/18 9:01 de la noche
in spanish.
A: Because the WhatsApp Android app formats dates like this
B: Because the Java 10 source code includes the following (From the german translation file):
<dayPeriods>
<dayPeriodContext type="format">
<dayPeriodWidth type="wide">
<dayPeriod type="afternoon">nachmittags</dayPeriod>
<dayPeriod type="am">vorm.</dayPeriod>
<dayPeriod type="earlyMorning">morgens</dayPeriod>
<dayPeriod type="evening">abends</dayPeriod>
<dayPeriod type="morning">vormittags</dayPeriod>
<dayPeriod type="night">nachts</dayPeriod>
<dayPeriod type="noon">Mittag</dayPeriod>
<dayPeriod type="pm">nachm.</dayPeriod>
</dayPeriodWidth>
</dayPeriodContext>
...
</dayPeriods>
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, current);
String formattedDate = df.format(System.currentTimeMillis());
Output: 08.12.18 7:24 nachm
or 8/12/18 7:54 p. m.
DateFormat abc = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, current);
abc.format(System.currentTimeMillis());
DateTimeFormatterBuilder
(With all of the AMPM_OF_DAY versions):
DateTimeFormatter test = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT);
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.append(test)
.appendText(ChronoField.AMPM_OF_DAY, TextStyle.SHORT)
.appendText(ChronoField.AMPM_OF_DAY, TextStyle.NARROW)
.appendText(ChronoField.AMPM_OF_DAY, TextStyle.FULL)
.appendText(ChronoField.AMPM_OF_DAY, TextStyle.FULL_STANDALONE)
.toFormatter(current);
ZonedDateTime date = ZonedDateTime.now();
date.format(fmt);
Output: 8 dic. 2018 19:54p. m.p. m.p. m.11
Is there any way i can output the date this way?
Thanks
Upvotes: 3
Views: 416
Reputation: 567
The day period support is there now with Java 16. The new formatter symbol "B" gives this support.
Example -
ZonedDateTime utcDateZoned = ZonedDateTime.now(ZoneId.of("Etc/UTC"));
System.out.println(utcDateZoned.format(DateTimeFormatter.ofPattern("dd:mm:yyy-h:mm B").withLocale(Locale.UK)));
System.out.println(utcDateZoned.format(DateTimeFormatter.ofPattern("dd:mm:yyy-h:mm B").withLocale(Locale.CHINA)));
System.out.println(utcDateZoned.format(DateTimeFormatter.ofPattern("dd:mm:yyy-h:mm B").withLocale(Locale.ITALY)));
System.out.println(utcDateZoned.format(DateTimeFormatter.ofPattern("dd:mm:yyy-h:mm B").withLocale(Locale.GERMAN)));
Output -
06:26:2023-4:26 in the afternoon
06:26:2023-4:26 下午
06:26:2023-4:26 del pomeriggio
06:26:2023-4:26 nachmittags
Upvotes: 0
Reputation: 44071
There are only two libraries which support day periods, namely ICU4J (partially incorporated in Android) and my lib Time4A. Other formatters like java.text.DateFormat
or java.time.format.DateTimeFormatter
have no support.
Example in Time4A for the German locale (here with a bridge to the old-fashioned type java.util.Date
):
ChronoFormatter<java.util.Date> f =
ChronoFormatter.ofPattern(
"dd.MM.uuuu, h:mm BBBB",
PatternType.CLDR,
Locale.GERMAN,
Moment.axis(TemporalType.JAVA_UTIL_DATE))
.withStdTimezone();
System.out.println(f.format(new java.util.Date()));
example output => "11.12.2018, 6:03 morgens"
It uses the special pattern symbol "B" defined by LDML-syntax of CLDR-data (managed by Unicode consortium). The day partition rules are also taken from CLDR data and look for German like:
# day-period-rules
T0000=night1
T0500=morning1
T1000=morning2
T1200=afternoon1
T1300=afternoon2
T1800=evening1
# day-period-translations
P(a)_morning1=morgens
P(a)_morning2=vormittags
P(a)_afternoon1=mittags
P(a)_afternoon2=nachmittags
P(a)_evening1=abends
P(a)_night1=nachts
If you don't agree with these data then you might construct your own customized formatter via the builder pattern.
Note about ICU4J: I have not tested that lib but maybe its class com.ibm.icu.text.SimpleDateFormat
supports the pattern symbol B, too (but then the javadoc is outdated).
Another note:
If you like style-based formatting without specifying a concrete pattern then you might go this way using a composition of date and time part:
Locale loc = Locale.US;
// our concrete values to be formatted
Moment moment = SystemClock.currentMoment();
PlainDate calendarDate = moment.toLocalTimestamp().getCalendarDate();
// get the localized clock pattern
Map<String, String> textForms = CalendarText.getIsoInstance(loc).getTextForms();
String pattern =
textForms.containsKey("F_Bhm") ? textForms.get("F_Bhm") : "h:mm B";
// construct the style-based date formatter
ChronoFormatter<PlainDate> f1 =
ChronoFormatter.ofDateStyle(DisplayMode.SHORT, loc);
// construct the time formatter
ChronoFormatter<Moment> f2 = ChronoFormatter.ofMomentPattern(
pattern,
PatternType.CLDR,
loc,
Timezone.ofSystem().getID());
System.out.println(f1.format(calendarDate) + " " + f2.format(moment));
// example output => "12/11/18 6:18 in the morning"
Upvotes: 3