Style-Based Formatters for Date and Time Values – Localization
By Gigi Rosen / January 24, 2022 / No Comments / Oracle Certifications, The ZonedDateTime Class
Style-Based Formatters for Date and Time Values
For more flexible formatters than the predefined ISO-based formatters, the Date-TimeFormatter class provides the static factory methods ofLocalizedType(), where Type is either Time, Date, or DateTime. These methods create formatters that use a specific format style. However, the format style cannot be changed after the formatter is created. Format styles are defined by the enum type java.time.format.Format-Style, and are shown in Table 18.12. The styles define format patterns that vary in their degree of verbosity.
The format style in a style-based formatter can be made locale-specific by setting the desired locale in the formatter using the localizedBy() method of the DateTime-Formatter class (p. 1128).
static DateTimeFormatter ofLocalizedTime(FormatStyle timeStyle)
static DateTimeFormatter ofLocalizedDate(FormatStyle dateStyle)
static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateTimeStyle)
static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateStyle,
FormatStylse timeStyle)
These static factory methods of the DateTimeFormatter class create a formatter that will format a time, a date, or a date-time, respectively, using the specified format style. The formatter can also be used to parse a character sequence for a time, a date, or a date-time, respectively.
In the discussion below, we will make use of the following temporal objects.
LocalTime time = LocalTime.of(14, 15, 30); // 14:15:30
LocalDate date = LocalDate.of(2021, 12, 1); // 2021-12-01
LocalDateTime dateTime = LocalDateTime.of(date, time); // 2021-12-01T14:15:30
// 2021-12-01T14:15:30-06:00[US/Central]
ZonedDateTime zonedDateTime = ZonedDateTime.of(dateTime, ZoneId.of(“US/Central”));
Table 18.13 shows which temporal classes can be formatted by a combination of a format style from Table 18.12 and an ofLocalizedType() method of the DateTimeFormatter class, where Type is either Time, Date, or DateTime. For example, in Table 18.13 we can see that the method call DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) will return a formatter that can be used to format instances of the LocalDate class, but will only format the date part of a LocalDateTime or a ZonedDateTime instance, as can be seen in the code below. This particular formatter requires date fields in the temporal object, and instances of these three temporal classes fit the bill.
Table 18.13 Using Style-Based Formatters
Using formatters created by factory methods of the DateTimeFormatter class: temporalReference.format(formatter) | |||
Format-Style | ofLocalizedTime(style) | ofLocalizedDate(style) | ofLocalizedDateTime(style) |
SHORT MEDIUM | LocalTime Time part of: LocalDateTime ZonedDateTime | LocalDate Date part of: LocalDateTime ZonedDateTime | LocalDateTime Date-time part of: ZonedDateTime |
LONG FULL | Time part of: ZonedDateTime | LocalDate Date part of: LocalDateTime ZonedDateTime | ZonedDateTime |
DateTimeFormatter dfs = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
String str1 = date.format(dfs); // 12/1/21
String str2 = dateTime.format(dfs); // Date part: 12/1/21
String str3 = zonedDateTime.format(dfs); // Date part: 12/1/21
Similarly, the method call DateTimeFormatter.ofLocalizedTime(FormatStyle.LONG) will return a formatter that will only format temporal objects that have a time part and are compatible with the rules of FormatStyle.LONG. Only instances of the Zoned-DateTime class fit the bill. The code below shows that we can format the time part of a ZonedDateTime instance with this formatter.
DateTimeFormatter tff = DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL);
String str4 = zonedDateTime.format(tff); // Time part:
// 2:15:30 PM Central Standard Time
String str5 = time.format(tff); // java.time.DateTimeException
String str6 = date.format(tff); // java.time.temporal.
// UnsupportedTemporalTypeException
String str7 = dateTime.format(tff); // java.time.DateTimeException
In summary, a style-based formatter will only format a temporal object (or its constituent parts) if the temporal object has the temporal parts required by the formatter and is compatible with the rules of the format style of the formatter.
Table 18.14 shows how the style-based formatters can be used as parsers. As in Table 18.13, this table also shows the combination of a format style from Table 18.12 and an ofLocalizedType() method of the DateTimeFormatter class, where Type is either Time, Date, or DateTime. From the table, we can read which temporal objects can be parsed from a character sequence that is compatible with the rules of a formatter for a given combination of the format style and a specific factory method.
Table 18.14 Using Style-Based Parsers
Using parsers created by factory methods of the DateTimeFormatter class: TemporalClass.parse(characterSequence,formatter) | |||
Format- Style | ofLocalizedTime(style) | ofLocalizedDate(style) | ofLocalizedDateTime(style) |
SHORT MEDIUM | LocalTime | LocalDate | LocalTime LocalDate LocalDateTime |
LONG FULL | LocalTime | LocalDate | LocalTime LocalDate LocalDateTime ZonedDateTime |
For any format style, the two methods ofLocalizedTime() and ofLocalizedDate() return formatters that can be used to parse a compatible character sequence to a LocalTime or a LocalDate instance, respectively.
In the code that follows, the date formatter created at (1) is used at (3) to parse the input string at (2) to create a LocalDate object.
DateTimeFormatter df = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);// (1)
String inputStr = “2/29/21”; // (2) en_US date, SHORT style
LocalDate parsedDate = LocalDate.parse(inputStr, df); // (3)
System.out.println(parsedDate); // (4) 2021-02-28
In the above code, the input string “2/29/21” is specified in the short style of the default locale (which in our case is the US locale). The input string is parsed by the date formatter (using the SHORT format style) to create a new LocalDate object.
Although the value 29 is invalid for the number of days in February for the year 2021, the output shows that it was adjusted correctly. The contents of the input string (in this case, “2/29/21”) must be compatible with the rules of the format style in the date formatter (in this case, FormatStyle.SHORT). If this is not the case, a DateTimeParse-Exception is thrown. Note that in the print statement at (4), the LocalDate object from the parsing is converted to a string by the LocalDate.toString() method using the implicit ISO-based formatter.
A formatter returned by the ofLocalizedDateTime() method can parse a character sequence to instances of different temporal classes, as shown in the rightmost column of Table 18.14. This is illustrated by the code below. Such a formatter is created at (1) and localized to the locale for France. It is first used to format a zoned date-time object at (2) to obtain a character string that we can parse with the formatter. At (3), (4), (5), and (6), this sequence is parsed to obtain a LocalTime, a Local-Date, a LocalDateTime, and a ZonedDateTime, respectively, as these temporal objects can be constructed from the format of the character string representing a zoned date-time.
DateTimeFormatter dtff
= DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL)
.localizedBy(Locale.FRANCE); // (1)
// “mercredi 1 décembre 2021 à 14:15:30 heure normale du centre nord-américain”
String charSeq = zonedDateTime.format(dtff); // (2)
LocalTime pTime = LocalTime.parse(charSeq, dtff); // (3) 14:15:30
LocalDate pDate = LocalDate.parse(charSeq, dtff); // (4) 2021-12-01
// 2021-12-01T14:15:30
LocalDateTime pDateTime = LocalDateTime.parse(charSeq, dtff); // (5)
// 2021-12-01T14:15:30-06:00[America/Chicago]
ZonedDateTime pZonedDateTime = ZonedDateTime.parse(charSeq, dtff); // (6)
In summary, a character sequence can be parsed to a temporal object by a style-based formatter if the character sequence is in the format required by the formatter to create the temporal object.