I need to parse different time format into BASIC_ISO_DATE
. Right now, there are 4 types of date format:
2016-10-01
(ISO_LOCAL_DATE)2016T
201610T
2016-02-07T22:03:39.937Z
(ISO 8601)
Need to parse to 20161001
and print out, with default day is 01
, default month Jan
. Examples:
2016T
->20160101
201610T
->20161001
How can I use DateTimeFormatter
to achieve this?
Just to complement @Flown's answer (which works perfectly BTW), you can also use optional patterns (delimited by []
):
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();
This works exactly the same way. You can choose which one is clearer or easier to maintain. If there are lots of different patterns, using []
might end up being more confusing, IMO.
Note that I used ISO_OFFSET_DATE_TIME
instead of ISO_ZONED_DATE_TIME
. The only difference is that ISO_ZONED_DATE_TIME
also accepts a timezone name in the end (like [Europe/London]
), while ISO_OFFSET_DATE_TIME
doesn't. Check the javadoc for more info.
You could build your own 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));
}
Try something like this:
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"));
}
If you want just one DateTimeFormatter
, Flown’s answer is well thought out and lends itself pretty well to adding more possible formats or changing the requirements in other ways.
I think a simple alternative is that you use three or four DateTimeFormatter
objects and try them in turn until one works.
For 2016T
, you may either use parseDefaulting()
as in Flown’s answer or just parse into a Year
and then use for example .atDay(1)
. Similarly for 201610T
: one option is to parse into a YearMonth
and use its atDay()
.
My solution may be less elegant, but possibly clearer to read.
来源:https://stackoverflow.com/questions/45748065/how-to-unify-date-format-using-datetimeformatter