如何使用 DateTimeFormatter 统一日期格式
How to unify date format using DateTimeFormatter
我需要将不同的时间格式解析为 BASIC_ISO_DATE
。目前,有 4 种类型的日期格式:
2016-10-01
(ISO_LOCAL_DATE)
2016T
201610T
2016-02-07T22:03:39.937Z
(ISO 8601)
需要解析为20161001
打印出来,默认日01
,默认月Jan
。示例:
2016T
-> 20160101
201610T
-> 20161001
如何使用 DateTimeFormatter
来实现这一点?
尝试这样的事情:
public LocalDate parse(String str) {
// Might want to add some checks here...
String text = (str.replaceAll("[\-T]", "") + "0101").substring(0, 8);
return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyyMMdd"));
}
您可以构建自己的 DateTimeFormatter
。
DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormatter.ISO_ZONED_DATE_TIME)
.appendOptional(DateTimeFormatter.ISO_LOCAL_DATE)
.appendOptional(new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.optionalStart()
.appendValue(ChronoField.MONTH_OF_YEAR)
.optionalEnd()
.appendLiteral('T')
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1L)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1L)
.toFormatter())
.toFormatter();
String[] strings = {"2016-10-01", "2016T", "201610T", "2016-02-07T22:03:39.937Z"};
for (String s : strings) {
System.out.println(LocalDate.parse(s, dateTimeFormatter)
.format(DateTimeFormatter.BASIC_ISO_DATE));
}
如果您只想要一个 DateTimeFormatter
, 是经过深思熟虑的,非常适合添加更多可能的格式或以其他方式更改要求。
我认为一个简单的替代方法是使用三个或四个 DateTimeFormatter
对象并依次尝试直到一个有效。
对于 2016T
,您可以像 Flown 的回答那样使用 parseDefaulting()
,或者只是解析为 Year
然后使用 .atDay(1)
。与 201610T
类似:一种选择是解析为 YearMonth
并使用其 atDay()
.
我的解决方案可能不太优雅,但可能更易读。
只是为了补充 (顺便说一句,效果很好),您还可以使用可选模式(由 []
分隔):
DateTimeFormatter parser = new DateTimeFormatterBuilder()
// optional ISO8601 date/time and offset
.appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
// optional yyyy-MM-dd or yyyyT or yyyyMMT
.appendPattern("[yyyy-MM-dd][yyyy'T'][yyyyMM'T']")
// default day is 1
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1L)
// default month is January
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1L)
// create formatter
.toFormatter();
这完全相同。您可以选择哪个更清晰或更易于维护。如果有 lots 不同的模式,使用 []
可能最终会更加混乱,IMO。
请注意,我使用 ISO_OFFSET_DATE_TIME
而不是 ISO_ZONED_DATE_TIME
。唯一的区别是 ISO_ZONED_DATE_TIME
最后也接受时区名称(如 [Europe/London]
),而 ISO_OFFSET_DATE_TIME
不接受。 Check the javadoc 获取更多信息。
我需要将不同的时间格式解析为 BASIC_ISO_DATE
。目前,有 4 种类型的日期格式:
2016-10-01
(ISO_LOCAL_DATE)2016T
201610T
2016-02-07T22:03:39.937Z
(ISO 8601)
需要解析为20161001
打印出来,默认日01
,默认月Jan
。示例:
2016T
->20160101
201610T
->20161001
如何使用 DateTimeFormatter
来实现这一点?
尝试这样的事情:
public LocalDate parse(String str) {
// Might want to add some checks here...
String text = (str.replaceAll("[\-T]", "") + "0101").substring(0, 8);
return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyyMMdd"));
}
您可以构建自己的 DateTimeFormatter
。
DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormatter.ISO_ZONED_DATE_TIME)
.appendOptional(DateTimeFormatter.ISO_LOCAL_DATE)
.appendOptional(new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.optionalStart()
.appendValue(ChronoField.MONTH_OF_YEAR)
.optionalEnd()
.appendLiteral('T')
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1L)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1L)
.toFormatter())
.toFormatter();
String[] strings = {"2016-10-01", "2016T", "201610T", "2016-02-07T22:03:39.937Z"};
for (String s : strings) {
System.out.println(LocalDate.parse(s, dateTimeFormatter)
.format(DateTimeFormatter.BASIC_ISO_DATE));
}
如果您只想要一个 DateTimeFormatter
,
我认为一个简单的替代方法是使用三个或四个 DateTimeFormatter
对象并依次尝试直到一个有效。
对于 2016T
,您可以像 Flown 的回答那样使用 parseDefaulting()
,或者只是解析为 Year
然后使用 .atDay(1)
。与 201610T
类似:一种选择是解析为 YearMonth
并使用其 atDay()
.
我的解决方案可能不太优雅,但可能更易读。
只是为了补充 []
分隔):
DateTimeFormatter parser = new DateTimeFormatterBuilder()
// optional ISO8601 date/time and offset
.appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
// optional yyyy-MM-dd or yyyyT or yyyyMMT
.appendPattern("[yyyy-MM-dd][yyyy'T'][yyyyMM'T']")
// default day is 1
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1L)
// default month is January
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1L)
// create formatter
.toFormatter();
这完全相同。您可以选择哪个更清晰或更易于维护。如果有 lots 不同的模式,使用 []
可能最终会更加混乱,IMO。
请注意,我使用 ISO_OFFSET_DATE_TIME
而不是 ISO_ZONED_DATE_TIME
。唯一的区别是 ISO_ZONED_DATE_TIME
最后也接受时区名称(如 [Europe/London]
),而 ISO_OFFSET_DATE_TIME
不接受。 Check the javadoc 获取更多信息。