如何从 system/context/locale 提供的 DateFormat 中去除年份
How to strip the year from the system/context/locale supplied DateFormat
我想要获取特定日期的 LocalDateTime
字符串表示形式。
目前提供的日期仍然是旧的 java.util.Date
对象。但是该方法应该使用现代LocalDate
API.
我想要实现的是用户当前语言环境中给定日期的简短表示。
我有三个案例:
- 同一天:仅显示用户语言环境格式的时间
- 同年:去除显示的年份但显示其余部分(日、月和时间)
- 其他:在用户语言环境中显示整个日期
我还希望将月份写为 Jan 或 Feb,而不是 01 或 02,如果这仍然与用户区域设置一致的话。
我的问题是:如何从特定于上下文的 DateFormat 中删除年份,以及如何获得月份不是 01 而是 Jan 的语言环境日期字符串。
这是我现在拥有的:
public static String getLocaleDateTimeStringShort(Context context, Date date) {
if (date != null && context != null) {
//TODO: Display Jan instead 01
LocalDateTime ld = date.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime();
LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(context);
DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(context);
if(ld.getDayOfMonth()==now.getDayOfMonth() && ld.getMonthValue()==now.getMonthValue() && ld.getYear()==now.getYear()) {
//Same day
return timeFormat.format(date);
} else if(ld.getYear()==now.getYear()){
//Same year
/* TODO: Strip year from date */
//dateFormat.
}else{
return dateFormat.format(date) + " " + timeFormat.format(date);
}
}
return null;
}
更新
我注意到对于我想要实现的目标可能存在混淆。让我们看一些例子:
使用德国 (dd MMM yy HH:mm) 和美国 (yy MMM dd HH:mm) 的语言环境:
如果两个语言环境在同一天发生某些事情,我想显示没有日期的时间:
德国:
- 11:33
州
- 11:33 上午(如果 phone 处于 12h 模式)
- 11:33(如果 phone 处于 24 小时模式)
现在,第二种情况是同一年内的日期:
德国:
- 8 月 29 日 11:33
州:
- 8 月 29 日 11:33
这里发生了什么?德国的正常模式是 dd MMM yyyy,而各州的正常模式是 yyyy MMM dd。因为如果年份与我们所在的年份相同,则不需要年份。我希望去掉年份。
不同年份:
德国:
- 19 年 8 月 30 日11:33
州
- 30 年 8 月 19 日11:33
(我实际上不确定我是否为各州使用了正确的日期时间模式,但我认为你可以明白这一点。我想保留特定于语言环境的 Date/DateTime 模式中的所有内容。但是去掉日期。
我尽管对它进行了 StringManipulating 并删除了其中的所有“y”
另一个更新:
您可以通过以下方式从模式中删除 year
部分:
public class Main {
public static void main(String[] args) {
// Test patterns
String[] patterns = { "MMM d, y, h:mm a", "d MMM y, HH:mm", "y年M月d日 ah:mm", "dd.MM.y, HH:mm", "y. M. d. a h:mm",
"d MMM y 'г'., HH:mm", "dd MMM y, HH:mm", "y/MM/dd H:mm", "d. MMM y, HH:mm", "dd/MM/y h:mm a",
"dd.M.y HH:mm", "d MMM y HH:mm" };
for (String pattern : patterns) {
System.out.println(pattern.replaceAll("([\s,.\/]\s*)?y+[.\/]?", "").trim());
}
}
}
输出:
MMM d, h:mm a
d MMM, HH:mm
年M月d日 ah:mm
dd.MM, HH:mm
M. d. a h:mm
d MMM 'г'., HH:mm
dd MMM, HH:mm
MM/dd H:mm
d. MMM, HH:mm
dd/MM h:mm a
dd.M HH:mm
d MMM HH:mm
您还可以查看 this 以获得更多解释和正则表达式演示。
正则表达式的解释:
([\s,.\/]\s*)?
指定一组可选的 space、逗号、点或正斜杠后跟任意数量的 spaces
y+
指定一个或多个y
[.\/]?
在 y+
之后指定一个可选的点或正斜杠
更新:
在原始答案中,date-time 部分固定在模式中的特定位置。我写了这个更新,因为 OP 要求帮助显示 locale-specific 部分 date-time 的位置。
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.FormatStyle;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// A sample java.util.Date instance
Date date = new Date();
// Convert Date into LocalDateTime at UTC
LocalDateTime ldt = date.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime();
// Instantiate Locale with the default locale
Locale locale = Locale.getDefault();
// Build a pattern for date
String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null,
IsoChronology.INSTANCE, locale);
// Build a pattern for time
String timePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(null, FormatStyle.MEDIUM,
IsoChronology.INSTANCE, locale);
// Build a pattern for date and time
String dateTimePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM,
FormatStyle.MEDIUM, IsoChronology.INSTANCE, locale);
System.out.println("Test reslts for my default locale:");
System.out.println(ldt.format(DateTimeFormatter.ofPattern(datePattern, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(timePattern, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(dateTimePattern, locale)));
// Let's test it for the Locale.GERMANY
locale = Locale.GERMANY;
System.out.println("\nTest reslts for Locale.GERMANY:");
String datePatternGermany = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null,
IsoChronology.INSTANCE, locale);
String timePatternGermany = DateTimeFormatterBuilder.getLocalizedDateTimePattern(null, FormatStyle.MEDIUM,
IsoChronology.INSTANCE, locale);
String dateTimePatternGermany = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM,
FormatStyle.MEDIUM, IsoChronology.INSTANCE, locale);
System.out.println(ldt.format(DateTimeFormatter.ofPattern(datePatternGermany, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(timePatternGermany, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(dateTimePatternGermany, locale)));
// Let's test it for the Locale.US
locale = Locale.US;
System.out.println("\nTest reslts for Locale.US:");
String datePatternUS = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null,
IsoChronology.INSTANCE, locale);
String timePatternUS = DateTimeFormatterBuilder.getLocalizedDateTimePattern(null, FormatStyle.MEDIUM,
IsoChronology.INSTANCE, locale);
String dateTimePatternUS = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM,
FormatStyle.MEDIUM, IsoChronology.INSTANCE, locale);
System.out.println(ldt.format(DateTimeFormatter.ofPattern(datePatternUS, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(timePatternUS, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(dateTimePatternUS, locale)));
}
}
输出:
Test reslts for my default locale:
30 Aug 2020
09:24:04
30 Aug 2020, 09:24:04
Test reslts for Locale.GERMANY:
30.08.2020
09:24:04
30.08.2020, 09:24:04
Test reslts for Locale.US:
Aug 30, 2020
9:24:04 AM
Aug 30, 2020, 9:24:04 AM
原回答:
根据您的问题,以下代码包含您需要的所有代码:
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// A sample java.util.Date instance
Date date = new Date();
// Convert Date into LocalDateTime at UTC
LocalDateTime ldt = date.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime();
// Get the string representing just time part
String sameDayDateTime = ldt.format(DateTimeFormatter.ofPattern("HH:mm:ss", Locale.getDefault()));
System.out.println(sameDayDateTime);
// Get the string representing all parts except year
String sameYearDateTime = ldt.format(DateTimeFormatter.ofPattern("MMM dd, HH:mm:ss", Locale.getDefault()));
System.out.println(sameYearDateTime);
// Display the default string representation of the date-time
String defaultDateTimeStr = ldt.toString();
System.out.println(defaultDateTimeStr);
// Display the string representation of the date-time in custom format
String customDateTimeStr = ldt
.format(DateTimeFormatter.ofPattern("yyyy MMM dd, HH:mm:ss", Locale.getDefault()));
System.out.println(customDateTimeStr);
}
}
输出:
21:37:24
Aug 28, 21:37:24
2020-08-28T21:37:24.697
2020 Aug 28, 21:37:24
因为你想 format/parse 没有年份,你不能使用 built-in 本地化格式,你必须建立自己的格式模式。
由于某些部分是可选的,您需要 3 个模式(完整、无年份和无日期)。完整模式可以是 re-used 用于解析,通过定义可选部分,并使用 parseDefaulting()
.
提供可选值
首先,这是一个为某些语言环境定义一些 date/time 格式模式的地图,以及获取特定模式的辅助方法:
private static final Map<Locale, List<String>> FORMATS = Map.of(
Locale.ENGLISH , List.of("[MMM d[, uuuu], ]h:mm a", "MMM d, h:mm a", "h:mm a"),
Locale.FRENCH , List.of("[d MMM[ uuuu] ]HH:mm" , "d MMM HH:mm" , "HH:mm" ),
Locale.GERMAN , List.of("[dd.MM[.uuuu], ]HH:mm" , "dd.MM, HH:mm" , "HH:mm" ),
Locale.JAPANESE, List.of("[[uuuu/]MM/dd ]H:mm" , "MM/dd H:mm" , "H:mm" )
);
private static String getFormat(Locale locale, int index) {
List<String> formats = FORMATS.get(locale);
if (formats == null)
throw new IllegalArgumentException("Format patterns not available for locale " + locale.toLanguageTag());
return formats.get(index);
}
Map.of()
和 List.of()
都是在 Java 9 中加入的,为了方便这里使用。
要格式化 LocalDateTime
,请使用此方法:
static String format(LocalDateTime dateTime, Locale locale) {
LocalDate today = LocalDate.now();
if (dateTime.toLocalDate().equals(today))
return dateTime.format(DateTimeFormatter.ofPattern(getFormat(locale, 2), locale));
if (dateTime.getYear() == today.getYear())
return dateTime.format(DateTimeFormatter.ofPattern(getFormat(locale, 1), locale));
return dateTime.format(DateTimeFormatter.ofPattern(getFormat(locale, 0), locale));
}
要将格式化字符串解析回 LocalDateTime
,请使用此方法,该方法使用 parseDefaulting()
提供今天的日期作为默认值:
static LocalDateTime parse(String dateTime, Locale locale) {
LocalDate today = LocalDate.now();
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern(getFormat(locale, 0))
.parseDefaulting(ChronoField.YEAR, today.getYear())
.parseDefaulting(ChronoField.MONTH_OF_YEAR, today.getMonthValue())
.parseDefaulting(ChronoField.DAY_OF_MONTH, today.getDayOfMonth())
.toFormatter(locale);
return LocalDateTime.parse(dateTime, formatter);
}
测试
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
FORMATS.keySet().stream().sorted(Comparator.comparing(Locale::getDisplayLanguage)).forEachOrdered(locale -> {
System.out.println(locale.getDisplayLanguage() + ":");
test(now.minusYears(1), locale);
test(now.minusDays(1), locale);
test(now, locale);
});
}
private static void test(LocalDateTime dateTime, Locale locale) {
String formatted = format(dateTime, locale);
LocalDateTime parsed = parse(formatted, locale);
System.out.printf(" %s formats to %-23s and parses back to %s%n", dateTime, formatted, parsed);
}
流只是用作对输出进行排序的便捷方式。
输出
English:
2019-08-30T08:20:59.126394500 formats to Aug 30, 2019, 8:20 AM and parses back to 2019-08-30T08:20
2020-08-29T08:20:59.126394500 formats to Aug 29, 8:20 AM and parses back to 2020-08-29T08:20
2020-08-30T08:20:59.126394500 formats to 8:20 AM and parses back to 2020-08-30T08:20
French:
2019-08-30T08:20:59.126394500 formats to 30 août 2019 08:20 and parses back to 2019-08-30T08:20
2020-08-29T08:20:59.126394500 formats to 29 août 08:20 and parses back to 2020-08-29T08:20
2020-08-30T08:20:59.126394500 formats to 08:20 and parses back to 2020-08-30T08:20
German:
2019-08-30T08:20:59.126394500 formats to 30.08.2019, 08:20 and parses back to 2019-08-30T08:20
2020-08-29T08:20:59.126394500 formats to 29.08, 08:20 and parses back to 2020-08-29T08:20
2020-08-30T08:20:59.126394500 formats to 08:20 and parses back to 2020-08-30T08:20
Japanese:
2019-08-30T08:20:59.126394500 formats to 2019/08/30 8:20 and parses back to 2019-08-30T08:20
2020-08-29T08:20:59.126394500 formats to 08/29 8:20 and parses back to 2020-08-29T08:20
2020-08-30T08:20:59.126394500 formats to 8:20 and parses back to 2020-08-30T08:20
我想要获取特定日期的 LocalDateTime
字符串表示形式。
目前提供的日期仍然是旧的 java.util.Date
对象。但是该方法应该使用现代LocalDate
API.
我想要实现的是用户当前语言环境中给定日期的简短表示。 我有三个案例:
- 同一天:仅显示用户语言环境格式的时间
- 同年:去除显示的年份但显示其余部分(日、月和时间)
- 其他:在用户语言环境中显示整个日期
我还希望将月份写为 Jan 或 Feb,而不是 01 或 02,如果这仍然与用户区域设置一致的话。
我的问题是:如何从特定于上下文的 DateFormat 中删除年份,以及如何获得月份不是 01 而是 Jan 的语言环境日期字符串。
这是我现在拥有的:
public static String getLocaleDateTimeStringShort(Context context, Date date) {
if (date != null && context != null) {
//TODO: Display Jan instead 01
LocalDateTime ld = date.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime();
LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(context);
DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(context);
if(ld.getDayOfMonth()==now.getDayOfMonth() && ld.getMonthValue()==now.getMonthValue() && ld.getYear()==now.getYear()) {
//Same day
return timeFormat.format(date);
} else if(ld.getYear()==now.getYear()){
//Same year
/* TODO: Strip year from date */
//dateFormat.
}else{
return dateFormat.format(date) + " " + timeFormat.format(date);
}
}
return null;
}
更新
我注意到对于我想要实现的目标可能存在混淆。让我们看一些例子:
使用德国 (dd MMM yy HH:mm) 和美国 (yy MMM dd HH:mm) 的语言环境:
如果两个语言环境在同一天发生某些事情,我想显示没有日期的时间:
德国:
- 11:33
州
- 11:33 上午(如果 phone 处于 12h 模式)
- 11:33(如果 phone 处于 24 小时模式)
现在,第二种情况是同一年内的日期:
德国:
- 8 月 29 日 11:33
州:
- 8 月 29 日 11:33
这里发生了什么?德国的正常模式是 dd MMM yyyy,而各州的正常模式是 yyyy MMM dd。因为如果年份与我们所在的年份相同,则不需要年份。我希望去掉年份。
不同年份:
德国:
- 19 年 8 月 30 日11:33
州
- 30 年 8 月 19 日11:33
(我实际上不确定我是否为各州使用了正确的日期时间模式,但我认为你可以明白这一点。我想保留特定于语言环境的 Date/DateTime 模式中的所有内容。但是去掉日期。
我尽管对它进行了 StringManipulating 并删除了其中的所有“y”
另一个更新:
您可以通过以下方式从模式中删除 year
部分:
public class Main {
public static void main(String[] args) {
// Test patterns
String[] patterns = { "MMM d, y, h:mm a", "d MMM y, HH:mm", "y年M月d日 ah:mm", "dd.MM.y, HH:mm", "y. M. d. a h:mm",
"d MMM y 'г'., HH:mm", "dd MMM y, HH:mm", "y/MM/dd H:mm", "d. MMM y, HH:mm", "dd/MM/y h:mm a",
"dd.M.y HH:mm", "d MMM y HH:mm" };
for (String pattern : patterns) {
System.out.println(pattern.replaceAll("([\s,.\/]\s*)?y+[.\/]?", "").trim());
}
}
}
输出:
MMM d, h:mm a
d MMM, HH:mm
年M月d日 ah:mm
dd.MM, HH:mm
M. d. a h:mm
d MMM 'г'., HH:mm
dd MMM, HH:mm
MM/dd H:mm
d. MMM, HH:mm
dd/MM h:mm a
dd.M HH:mm
d MMM HH:mm
您还可以查看 this 以获得更多解释和正则表达式演示。
正则表达式的解释:
([\s,.\/]\s*)?
指定一组可选的 space、逗号、点或正斜杠后跟任意数量的 spacesy+
指定一个或多个y
[.\/]?
在y+
之后指定一个可选的点或正斜杠
更新:
在原始答案中,date-time 部分固定在模式中的特定位置。我写了这个更新,因为 OP 要求帮助显示 locale-specific 部分 date-time 的位置。
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.FormatStyle;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// A sample java.util.Date instance
Date date = new Date();
// Convert Date into LocalDateTime at UTC
LocalDateTime ldt = date.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime();
// Instantiate Locale with the default locale
Locale locale = Locale.getDefault();
// Build a pattern for date
String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null,
IsoChronology.INSTANCE, locale);
// Build a pattern for time
String timePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(null, FormatStyle.MEDIUM,
IsoChronology.INSTANCE, locale);
// Build a pattern for date and time
String dateTimePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM,
FormatStyle.MEDIUM, IsoChronology.INSTANCE, locale);
System.out.println("Test reslts for my default locale:");
System.out.println(ldt.format(DateTimeFormatter.ofPattern(datePattern, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(timePattern, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(dateTimePattern, locale)));
// Let's test it for the Locale.GERMANY
locale = Locale.GERMANY;
System.out.println("\nTest reslts for Locale.GERMANY:");
String datePatternGermany = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null,
IsoChronology.INSTANCE, locale);
String timePatternGermany = DateTimeFormatterBuilder.getLocalizedDateTimePattern(null, FormatStyle.MEDIUM,
IsoChronology.INSTANCE, locale);
String dateTimePatternGermany = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM,
FormatStyle.MEDIUM, IsoChronology.INSTANCE, locale);
System.out.println(ldt.format(DateTimeFormatter.ofPattern(datePatternGermany, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(timePatternGermany, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(dateTimePatternGermany, locale)));
// Let's test it for the Locale.US
locale = Locale.US;
System.out.println("\nTest reslts for Locale.US:");
String datePatternUS = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null,
IsoChronology.INSTANCE, locale);
String timePatternUS = DateTimeFormatterBuilder.getLocalizedDateTimePattern(null, FormatStyle.MEDIUM,
IsoChronology.INSTANCE, locale);
String dateTimePatternUS = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM,
FormatStyle.MEDIUM, IsoChronology.INSTANCE, locale);
System.out.println(ldt.format(DateTimeFormatter.ofPattern(datePatternUS, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(timePatternUS, locale)));
System.out.println(ldt.format(DateTimeFormatter.ofPattern(dateTimePatternUS, locale)));
}
}
输出:
Test reslts for my default locale:
30 Aug 2020
09:24:04
30 Aug 2020, 09:24:04
Test reslts for Locale.GERMANY:
30.08.2020
09:24:04
30.08.2020, 09:24:04
Test reslts for Locale.US:
Aug 30, 2020
9:24:04 AM
Aug 30, 2020, 9:24:04 AM
原回答:
根据您的问题,以下代码包含您需要的所有代码:
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// A sample java.util.Date instance
Date date = new Date();
// Convert Date into LocalDateTime at UTC
LocalDateTime ldt = date.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime();
// Get the string representing just time part
String sameDayDateTime = ldt.format(DateTimeFormatter.ofPattern("HH:mm:ss", Locale.getDefault()));
System.out.println(sameDayDateTime);
// Get the string representing all parts except year
String sameYearDateTime = ldt.format(DateTimeFormatter.ofPattern("MMM dd, HH:mm:ss", Locale.getDefault()));
System.out.println(sameYearDateTime);
// Display the default string representation of the date-time
String defaultDateTimeStr = ldt.toString();
System.out.println(defaultDateTimeStr);
// Display the string representation of the date-time in custom format
String customDateTimeStr = ldt
.format(DateTimeFormatter.ofPattern("yyyy MMM dd, HH:mm:ss", Locale.getDefault()));
System.out.println(customDateTimeStr);
}
}
输出:
21:37:24
Aug 28, 21:37:24
2020-08-28T21:37:24.697
2020 Aug 28, 21:37:24
因为你想 format/parse 没有年份,你不能使用 built-in 本地化格式,你必须建立自己的格式模式。
由于某些部分是可选的,您需要 3 个模式(完整、无年份和无日期)。完整模式可以是 re-used 用于解析,通过定义可选部分,并使用 parseDefaulting()
.
首先,这是一个为某些语言环境定义一些 date/time 格式模式的地图,以及获取特定模式的辅助方法:
private static final Map<Locale, List<String>> FORMATS = Map.of(
Locale.ENGLISH , List.of("[MMM d[, uuuu], ]h:mm a", "MMM d, h:mm a", "h:mm a"),
Locale.FRENCH , List.of("[d MMM[ uuuu] ]HH:mm" , "d MMM HH:mm" , "HH:mm" ),
Locale.GERMAN , List.of("[dd.MM[.uuuu], ]HH:mm" , "dd.MM, HH:mm" , "HH:mm" ),
Locale.JAPANESE, List.of("[[uuuu/]MM/dd ]H:mm" , "MM/dd H:mm" , "H:mm" )
);
private static String getFormat(Locale locale, int index) {
List<String> formats = FORMATS.get(locale);
if (formats == null)
throw new IllegalArgumentException("Format patterns not available for locale " + locale.toLanguageTag());
return formats.get(index);
}
Map.of()
和 List.of()
都是在 Java 9 中加入的,为了方便这里使用。
要格式化 LocalDateTime
,请使用此方法:
static String format(LocalDateTime dateTime, Locale locale) {
LocalDate today = LocalDate.now();
if (dateTime.toLocalDate().equals(today))
return dateTime.format(DateTimeFormatter.ofPattern(getFormat(locale, 2), locale));
if (dateTime.getYear() == today.getYear())
return dateTime.format(DateTimeFormatter.ofPattern(getFormat(locale, 1), locale));
return dateTime.format(DateTimeFormatter.ofPattern(getFormat(locale, 0), locale));
}
要将格式化字符串解析回 LocalDateTime
,请使用此方法,该方法使用 parseDefaulting()
提供今天的日期作为默认值:
static LocalDateTime parse(String dateTime, Locale locale) {
LocalDate today = LocalDate.now();
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern(getFormat(locale, 0))
.parseDefaulting(ChronoField.YEAR, today.getYear())
.parseDefaulting(ChronoField.MONTH_OF_YEAR, today.getMonthValue())
.parseDefaulting(ChronoField.DAY_OF_MONTH, today.getDayOfMonth())
.toFormatter(locale);
return LocalDateTime.parse(dateTime, formatter);
}
测试
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
FORMATS.keySet().stream().sorted(Comparator.comparing(Locale::getDisplayLanguage)).forEachOrdered(locale -> {
System.out.println(locale.getDisplayLanguage() + ":");
test(now.minusYears(1), locale);
test(now.minusDays(1), locale);
test(now, locale);
});
}
private static void test(LocalDateTime dateTime, Locale locale) {
String formatted = format(dateTime, locale);
LocalDateTime parsed = parse(formatted, locale);
System.out.printf(" %s formats to %-23s and parses back to %s%n", dateTime, formatted, parsed);
}
流只是用作对输出进行排序的便捷方式。
输出
English:
2019-08-30T08:20:59.126394500 formats to Aug 30, 2019, 8:20 AM and parses back to 2019-08-30T08:20
2020-08-29T08:20:59.126394500 formats to Aug 29, 8:20 AM and parses back to 2020-08-29T08:20
2020-08-30T08:20:59.126394500 formats to 8:20 AM and parses back to 2020-08-30T08:20
French:
2019-08-30T08:20:59.126394500 formats to 30 août 2019 08:20 and parses back to 2019-08-30T08:20
2020-08-29T08:20:59.126394500 formats to 29 août 08:20 and parses back to 2020-08-29T08:20
2020-08-30T08:20:59.126394500 formats to 08:20 and parses back to 2020-08-30T08:20
German:
2019-08-30T08:20:59.126394500 formats to 30.08.2019, 08:20 and parses back to 2019-08-30T08:20
2020-08-29T08:20:59.126394500 formats to 29.08, 08:20 and parses back to 2020-08-29T08:20
2020-08-30T08:20:59.126394500 formats to 08:20 and parses back to 2020-08-30T08:20
Japanese:
2019-08-30T08:20:59.126394500 formats to 2019/08/30 8:20 and parses back to 2019-08-30T08:20
2020-08-29T08:20:59.126394500 formats to 08/29 8:20 and parses back to 2020-08-29T08:20
2020-08-30T08:20:59.126394500 formats to 8:20 and parses back to 2020-08-30T08:20