使用 DateTimeFormatter.ofLocalizedDate 格式化 MonthDay
Formatting MonthDay using DateTimeFormatter.ofLocalizedDate
我正在尝试格式化 MonthDay
object in a way that I do not have to specify the order. I am trying to use a localized DateTimeFormatter
。
我有这个代码:
LocalDate datetime = LocalDate.parse("2017-08-11", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
MonthDay monthday = MonthDay.from(datetime);
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.ENGLISH)));
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.GERMANY)));
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.forLanguageTag("UK"))));
System.out.println(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH)));
System.out.println(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
// next line throws exception for java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
System.out.println(monthday.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
前 3 次打印将按预期打印翻译后的月份和日期,但始终是先是月份再是日期。它不会更改顺序,因为我明确告诉它顺序。
接下来的两个(异常前)将分别打印:
Aug 11, 2017
11 серп. 2017
请注意日期是在月份之前还是之后,具体取决于传递给函数的语言环境。我如何使用 MonthDay
对象执行此操作,因为最后一行在以这种方式完成时抛出异常。
MonthDay
不存储年份信息,FormatStyle.MEDIUM
需要一个年份值,这就是格式化程序找不到字段的原因 YearOfEra
如果您使用 [=13,也会发生同样的情况=] 具有相同的 FormatStyle
,但现在缺少字段 DayOfMonth
。
This class does not store or represent a year, time or time-zone. For example, the value "December 3rd" can be stored in a MonthDay.
您可以将 monthday
转换为 Instant 或简单地使用 datetime
.
ofLocalizedDate
returns 日期的格式化程序,因此它格式化 day、month 和 year 字段,因此被格式化的对象需要具有所有三个字段。 MonthDay
没有 year 字段,这就是它抛出 UnsupportedTemporalTypeException
.
的原因
如果要打印整个日期(日、月和年 ),您必须将年份添加到 MonthDay
对象。您可以为此使用 atYear
方法:
System.out.println(monthday.atYear(2017).format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
这将输出:
11 серп. 2017
如果您想要当前年份,只需使用 Year.now().getValue()
而不是 2017
。
您也可以使用 datetime.getYear()
,如果您想要 LocalDate
的同一年 - 或者使用 datetime
而不是 monthday
。
如果您只想打印 日 和 月 ,则必须采取一些变通办法。
由于本地化格式化程序内置于 JDK 中(而且似乎无法更改它们),您没有直接的方法来做,尽管有一些替代方法.
一个(丑陋的)解决方案是设置年份,然后将其从格式化的 String
:
中删除
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"));
// set year to 2017, then remove "2017" from the formatted string
System.out.println(monthday.atYear(2017).format(formatter).replace("2017", "").trim());
输出为:
11 серп.
无聊的部分是删除每个语言环境中可能存在的所有额外字符。对于英语语言环境,我还必须删除 ,
:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH);
// remove the year (2017) and the "," from the output
System.out.println(monthday.atYear(2017).format(formatter).replace("2017", "").replace(",", "").trim());
输出为:
Aug 11
您必须检查所有区域设置的所有额外字符(例如 ,
),并将它们从输出中删除。或者只是将 ofPattern
与固定的非语言环境特定模式一起使用(就像您在前 3 次测试中所做的那样)。
与 一样,我假设年份处于模式的开头或结尾。如果年份在中间,最后的结果会有一些多余的空格,可以用.replaceAll("\s{2,}", " ")
去掉(2个以上的空格只换成1个)
另一种选择(如 所建议)是使用 DateTimeFormatterBuilder
来获取本地化的日期模式。
然后我从模式中删除年份,替换 y
和 u
(patterns used for the year),并删除一些其他字符(如 ,
和额外的空格)。
使用生成的模式(没有年份),我使用指定的语言环境创建了一个 DateTimeFormatter
并格式化了 MonthDay
:
// get date pattern for the specified locale
String pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.forLanguageTag("UK"));
pattern = pattern
// remove the year (1 or more occurrences of "y" or "u")
.replaceAll("[yu]+", "")
// replace "," (you can change this to remove any other characters you want)
.replaceAll(",", "")
// replace 2 or more spaces with just one space and trim to remove spaces in the start or end
.replaceAll("\s{2,}", " ").trim();
// create formatter for the pattern and locale
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern, Locale.forLanguageTag("UK"));
System.out.println(monthday.format(fmt));
输出将是:
11 серп.
提醒一下,这个例子可能不完整,因为有一些语言环境使用/
、-
和其他字符作为分隔符,你必须从最终结果中删除它们。检查您正在使用的所有语言环境并相应地删除字符。
另一个未涵盖的极端情况是当您将 y
或 u
作为文字(在 '
内)时:在这种情况下,不应删除它们。无论如何,您必须检查您正在使用的所有语言环境的格式并相应地处理每种情况。
到目前为止给出的其他答案描述了标准的局限性DateTimeFormatter
,另请参阅未解决的相关问题JDK-issue。建议的通过删除 "y" 等来编辑本地化日期模式的解决方法很棘手,并且由于模式中存在其他本地化文字,可能不适用于所有语言环境。
但是,您也可以考虑使用更注重国际化问题的外部库,并且能够仅使用语言环境信息来格式化月-日-对象。所以语言环境决定了字段组件以及点、空格或其他特殊文字(如中文)的顺序。
这里有两个选项,其中包含与您的系统时区相关的必要类型转换:
ICU4J
MonthDay md = MonthDay.now();
GregorianCalendar gcal =
new GregorianCalendar(
2000, // avoids possible leap year problems
md.getMonthValue() - 1,
md.getDayOfMonth()
);
DateFormat df =
DateFormat.getInstanceForSkeleton(
DateFormat.ABBR_MONTH_DAY,
Locale.forLanguageTag("en")
);
System.out.println(df.format(gcal.getTime())); // Aug 15
DateFormat df2 =
DateFormat.getInstanceForSkeleton(
DateFormat.ABBR_MONTH_DAY,
Locale.forLanguageTag("de")
);
System.out.println(df2.format(gcal.getTime())); // 15. Aug.
DateFormat df3 =
DateFormat.getInstanceForSkeleton(DateFormat.MONTH_DAY, Locale.forLanguageTag("zh"));
System.out.println(df3.format(gcal.getTime())); // 8月15日
Time4J
MonthDay md = MonthDay.now();
ChronoFormatter<AnnualDate> cf1 =
ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf1.format(AnnualDate.from(md))); // 15.8.
ChronoFormatter<AnnualDate> cf2 =
ChronoFormatter.ofStyle(DisplayMode.MEDIUM, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf2.format(AnnualDate.from(md))); // 15.08.
ChronoFormatter<AnnualDate> cf3 =
ChronoFormatter.ofStyle(DisplayMode.LONG, Locale.ENGLISH, AnnualDate.chronology());
System.out.println(cf3.format(AnnualDate.from(md))); // Aug 15
ChronoFormatter<AnnualDate> cf4 =
ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf4.format(AnnualDate.from(md))); // 15. August
ChronoFormatter<AnnualDate> cf5 =
ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.CHINESE, AnnualDate.chronology());
System.out.println(cf5.format(AnnualDate.from(md))); // 8月15日
免责声明:我自己编写了 Time4J 以填补空白或改进 JSR-310(java.time-包)的其他功能。
我正在尝试格式化 MonthDay
object in a way that I do not have to specify the order. I am trying to use a localized DateTimeFormatter
。
我有这个代码:
LocalDate datetime = LocalDate.parse("2017-08-11", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
MonthDay monthday = MonthDay.from(datetime);
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.ENGLISH)));
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.GERMANY)));
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.forLanguageTag("UK"))));
System.out.println(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH)));
System.out.println(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
// next line throws exception for java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
System.out.println(monthday.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
前 3 次打印将按预期打印翻译后的月份和日期,但始终是先是月份再是日期。它不会更改顺序,因为我明确告诉它顺序。
接下来的两个(异常前)将分别打印:
Aug 11, 2017
11 серп. 2017
请注意日期是在月份之前还是之后,具体取决于传递给函数的语言环境。我如何使用 MonthDay
对象执行此操作,因为最后一行在以这种方式完成时抛出异常。
MonthDay
不存储年份信息,FormatStyle.MEDIUM
需要一个年份值,这就是格式化程序找不到字段的原因 YearOfEra
如果您使用 [=13,也会发生同样的情况=] 具有相同的 FormatStyle
,但现在缺少字段 DayOfMonth
。
This class does not store or represent a year, time or time-zone. For example, the value "December 3rd" can be stored in a MonthDay.
您可以将 monthday
转换为 Instant 或简单地使用 datetime
.
ofLocalizedDate
returns 日期的格式化程序,因此它格式化 day、month 和 year 字段,因此被格式化的对象需要具有所有三个字段。 MonthDay
没有 year 字段,这就是它抛出 UnsupportedTemporalTypeException
.
如果要打印整个日期(日、月和年 ),您必须将年份添加到 MonthDay
对象。您可以为此使用 atYear
方法:
System.out.println(monthday.atYear(2017).format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
这将输出:
11 серп. 2017
如果您想要当前年份,只需使用 Year.now().getValue()
而不是 2017
。
您也可以使用 datetime.getYear()
,如果您想要 LocalDate
的同一年 - 或者使用 datetime
而不是 monthday
。
如果您只想打印 日 和 月 ,则必须采取一些变通办法。
由于本地化格式化程序内置于 JDK 中(而且似乎无法更改它们),您没有直接的方法来做,尽管有一些替代方法.
一个(丑陋的)解决方案是设置年份,然后将其从格式化的 String
:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"));
// set year to 2017, then remove "2017" from the formatted string
System.out.println(monthday.atYear(2017).format(formatter).replace("2017", "").trim());
输出为:
11 серп.
无聊的部分是删除每个语言环境中可能存在的所有额外字符。对于英语语言环境,我还必须删除 ,
:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH);
// remove the year (2017) and the "," from the output
System.out.println(monthday.atYear(2017).format(formatter).replace("2017", "").replace(",", "").trim());
输出为:
Aug 11
您必须检查所有区域设置的所有额外字符(例如 ,
),并将它们从输出中删除。或者只是将 ofPattern
与固定的非语言环境特定模式一起使用(就像您在前 3 次测试中所做的那样)。
与 .replaceAll("\s{2,}", " ")
去掉(2个以上的空格只换成1个)
另一种选择(如 DateTimeFormatterBuilder
来获取本地化的日期模式。
然后我从模式中删除年份,替换 y
和 u
(patterns used for the year),并删除一些其他字符(如 ,
和额外的空格)。
使用生成的模式(没有年份),我使用指定的语言环境创建了一个 DateTimeFormatter
并格式化了 MonthDay
:
// get date pattern for the specified locale
String pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.forLanguageTag("UK"));
pattern = pattern
// remove the year (1 or more occurrences of "y" or "u")
.replaceAll("[yu]+", "")
// replace "," (you can change this to remove any other characters you want)
.replaceAll(",", "")
// replace 2 or more spaces with just one space and trim to remove spaces in the start or end
.replaceAll("\s{2,}", " ").trim();
// create formatter for the pattern and locale
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern, Locale.forLanguageTag("UK"));
System.out.println(monthday.format(fmt));
输出将是:
11 серп.
提醒一下,这个例子可能不完整,因为有一些语言环境使用/
、-
和其他字符作为分隔符,你必须从最终结果中删除它们。检查您正在使用的所有语言环境并相应地删除字符。
另一个未涵盖的极端情况是当您将 y
或 u
作为文字(在 '
内)时:在这种情况下,不应删除它们。无论如何,您必须检查您正在使用的所有语言环境的格式并相应地处理每种情况。
到目前为止给出的其他答案描述了标准的局限性DateTimeFormatter
,另请参阅未解决的相关问题JDK-issue。建议的通过删除 "y" 等来编辑本地化日期模式的解决方法很棘手,并且由于模式中存在其他本地化文字,可能不适用于所有语言环境。
但是,您也可以考虑使用更注重国际化问题的外部库,并且能够仅使用语言环境信息来格式化月-日-对象。所以语言环境决定了字段组件以及点、空格或其他特殊文字(如中文)的顺序。
这里有两个选项,其中包含与您的系统时区相关的必要类型转换:
ICU4J
MonthDay md = MonthDay.now();
GregorianCalendar gcal =
new GregorianCalendar(
2000, // avoids possible leap year problems
md.getMonthValue() - 1,
md.getDayOfMonth()
);
DateFormat df =
DateFormat.getInstanceForSkeleton(
DateFormat.ABBR_MONTH_DAY,
Locale.forLanguageTag("en")
);
System.out.println(df.format(gcal.getTime())); // Aug 15
DateFormat df2 =
DateFormat.getInstanceForSkeleton(
DateFormat.ABBR_MONTH_DAY,
Locale.forLanguageTag("de")
);
System.out.println(df2.format(gcal.getTime())); // 15. Aug.
DateFormat df3 =
DateFormat.getInstanceForSkeleton(DateFormat.MONTH_DAY, Locale.forLanguageTag("zh"));
System.out.println(df3.format(gcal.getTime())); // 8月15日
Time4J
MonthDay md = MonthDay.now();
ChronoFormatter<AnnualDate> cf1 =
ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf1.format(AnnualDate.from(md))); // 15.8.
ChronoFormatter<AnnualDate> cf2 =
ChronoFormatter.ofStyle(DisplayMode.MEDIUM, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf2.format(AnnualDate.from(md))); // 15.08.
ChronoFormatter<AnnualDate> cf3 =
ChronoFormatter.ofStyle(DisplayMode.LONG, Locale.ENGLISH, AnnualDate.chronology());
System.out.println(cf3.format(AnnualDate.from(md))); // Aug 15
ChronoFormatter<AnnualDate> cf4 =
ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf4.format(AnnualDate.from(md))); // 15. August
ChronoFormatter<AnnualDate> cf5 =
ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.CHINESE, AnnualDate.chronology());
System.out.println(cf5.format(AnnualDate.from(md))); // 8月15日
免责声明:我自己编写了 Time4J 以填补空白或改进 JSR-310(java.time-包)的其他功能。