Java 8 time/LocalDate:将日期从一种格式转换为本地特定格式



我从服务器调用、日期字符串和用户区域设置中获得两条信息

String originalDateStr = serverCallToGetADate().getDate();
String localeString = serverCallToGetADate().getLocaleString();

无论区域设置如何,日期都保证为以下格式

yyyy-MM-dd

区域设置是IETF语言代码,例如

en-US fr-FR es-ES de-DE etc 

我可以使用为日期创建LocalDate对象

DateTimeFormatter originalFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate originalDate = LocalDate.parse(originalDateStr, originalFormatter);

我现在想打印出只有年作为4个数字、月作为2个数字和日作为2个号码的日期-"在值之间,并使用我也从服务器接收到的区域设置字符串。例如,如果日期是2021年7月31日,我想将该日期呈现为

  • 英国:2021年7月31日
  • 美国:2021年7月31日
  • 日本:2021-07-31

我不知道该怎么做。这就是我尝试过的

@Test
public void testFormatting() {
String SERVER_FORMAT = "yyyy-MM-dd";
String SERVER_TEST_DATE = "2021-07-31";
DateTimeFormatter serverFormatter = DateTimeFormatter.ofPattern(SERVER_FORMAT);
// can only create a LocalDate from the server value as there is no time part in the string
LocalDate testDate = LocalDate.parse(SERVER_TEST_DATE, serverFormatter);
System.out.println("Original Server Date Value = " + testDate.format(serverFormatter));
System.out.println("nUsing : testDate.format(serverFormatter.withLocale(locale) - Doesn't work");
Locale localeUS = Locale.forLanguageTag("en-US");
Locale localeUK = Locale.forLanguageTag("en-GB");
System.out.println("Attempting US (should be 07-31-2021) = " + testDate.format(serverFormatter.withLocale(localeUS)));
System.out.println("Attempting UK (should be 31-07-2021) = " + testDate.format(serverFormatter.withLocale(localeUK)));

// in order to use the following coed these we need a time part for the date, so put to start of day
System.out.println("nUsing DateTimeFormatterBuilder - wrong as it includes / or , and has time displayed");
LocalDateTime testDateTime = testDate.atStartOfDay();
String datePattern_short = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
FormatStyle.SHORT, FormatStyle.MEDIUM, Chronology.ofLocale(localeUS), localeUS);
DateTimeFormatter dateFormatterShort = DateTimeFormatter.ofPattern(datePattern_short);
System.out.println("datePattern SHORT US (should be 07-31-2021)  = " + testDateTime.format(dateFormatterShort));
String datePattern_medium = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
FormatStyle.MEDIUM, FormatStyle.MEDIUM, Chronology.ofLocale(localeUS), localeUS);
DateTimeFormatter dateFormatterMedium = DateTimeFormatter.ofPattern(datePattern_medium);
System.out.println("datePattern MEDIUM US (should be 07-31-2021)  = " + testDateTime.format(dateFormatterMedium));
String datePattern_long = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
FormatStyle.LONG, FormatStyle.MEDIUM, Chronology.ofLocale(localeUS), localeUS);
DateTimeFormatter dateFormatterLong = DateTimeFormatter.ofPattern(datePattern_long);
System.out.println("datePattern LONG US (should be 07-31-2021)  = " + testDateTime.format(dateFormatterLong));
}

输出

Original Server Date Value = 2021-07-31
Using : testDate.format(serverFormatter.withLocale(locale) - Doesn't work
Attempting US (should be 07-31-2021) = 2021-07-31
Attempting UK (should be 31-07-2021) = 2021-07-31
Using DateTimeFormatterBuilder - wrong as it includes / or , and has time displayed
datePattern SHORT US (should be 07-31-2021)  = 7/31/21, 12:00:00 am
datePattern MEDIUM US (should be 07-31-2021)  = Jul 31, 2021, 12:00:00 am
datePattern LONG US (should be 07-31-2021)  = July 31, 2021, 12:00:00 am

Sweeper在他们的评论中给出了答案。

我试图做的事情是无效的。我应该始终使用区域设置时区的标准格式。

我不确定你为什么认为你想要这个,并倾向于接受Sweeper的建议:你应该相信Java从CLDR(Unicode通用区域设置数据库(和/或其他来源获得的本地化格式模式。我不认为世界各地的用户会对你在任何地方强制使用连字符的格式感到高兴。

但是,如果您坚持,可以通过一些更简单的正则表达式根据您的需求修改从DateTimeFormatterBuilder获得的格式模式字符串。

String[] tags = { "en-US", "fr-FR", "es-ES", "de-DE", "jp-JP" };
LocalDate sampleDate = LocalDate.of(2021, Month.JULY, 31);
for (String langTag : tags) {
Locale loc = Locale.forLanguageTag(langTag);
String pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
FormatStyle.SHORT, null, IsoChronology.INSTANCE, loc);
// Ensure full year and 2-digit month and day
pattern = pattern.replaceAll("y+", "y")
.replaceAll("M+", "MM")
.replaceAll("d+", "dd");
// Change punctuation to hyphens
pattern = pattern.replaceFirst("^\W+", "")
.replaceFirst("\W+$", "")
.replaceAll("\W+", "-");
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern);
System.out.format("%-5s -> %s%n", langTag, sampleDate.format(dateFormatter));
}

这个片段的输出是:

en-US -> 07-31-2021
fr-FR -> 31-07-2021
es-ES -> 31-07-2021
de-DE -> 31-07-2021
jp-JP -> 2021-07-31

我相信,如果模式中有两个或多个字段相邻,例如yyMM,我的代码将无法插入连字符。我不知道这种情况是否适用于任何语言环境。此外,它不会删除某些地区格式中的任何文字字母。因此,将其作为一个起点,并根据您的需求进行改进。您可能希望使用JVM中所有可用的区域设置进行测试。

最新更新