您可以使用可選部分模式(由[]
定界),並創建3個可選部分:1個用於9位數字,另一個用於6位數字,另一個用於3位數字。
據DateTimeFormatterBuilder
docs,您可以使用S
模式(這相當於NANO_OF_SECOND field):
Pattern Count Equivalent builder methods
------- ----- --------------------------
S..S 1..n appendFraction(ChronoField.NANO_OF_SECOND, n, n, false)
在舊的API(SimpleDateFormat
),S
is the pattern used for milliseconds,但新的API中又改爲納秒。
所以格式化會這樣創建:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// here is the same as your code
.append(DateTimeFormatter.BASIC_ISO_DATE).appendLiteral('-')
// time (hour/minute/seconds)
.appendPattern("HH:mm:ss")
// optional nanos, with 9, 6 or 3 digits
.appendPattern("[.SSSSSSSSS][.SSSSSS][.SSS]")
// offset
.appendOffset("+HH:mm", "Z")
// create formatter
.toFormatter();
一些測試:
// 3 digits
System.out.println(OffsetDateTime.parse("20161201-10:30:45.123Z", formatter)); // 2016-12-01T10:30:45.123Z
// 6 digits
System.out.println(OffsetDateTime.parse("20161201-10:30:45.123456Z", formatter)); // 2016-12-01T10:30:45.123456Z
// 9 digits
System.out.println(OffsetDateTime.parse("20161201-10:30:45.123456789Z", formatter)); // 2016-12-01T10:30:45.123456789Z
// 4 digits (throws DateTimeParseException: Text '20161201-10:30:45.1234Z' could not be parsed at index 21)
System.out.println(OffsetDateTime.parse("20161201-10:30:45.1234Z", formatter));
輸出是:
2016-12-01T10:30:45.123 Z
2016-12-01T10:30:45.123456Z
2016-12-01T10:30:45.123456789Z
線程「main」中的異常java.time.format.DateTimeParseException:Text'20161201-10:30:45。
注意事項解析所以納秒將被打印3次):
// don't use it to format, it prints all optional sections
// (so nanos are printed 3 times: with 9, 6 and 3 digits)
OffsetDateTime odt = OffsetDateTime.parse("20161201-10:30:45.123Z", formatter);
System.out.println(formatter.format(odt));
// output is 20161201Z-10:30:45.123000000.123000.123Z
因此,如果您想以其他格式顯示日期,請考慮創建另一個DateTimeFormatter
。
在您的代碼中,您使用了DateTimeFormatter.ISO_LOCAL_TIME
。根據javadoc,在此格式化程序中,秒是可選的。如果你想有相同的行爲,只是改變了時間模式:
// time (hour/minute) with optional seconds
.appendPattern("HH:mm[:ss]")
的[]
模式是一個很好的快捷方式,使其可選部分,但你也可以將它們使用創建optionalStart()
與appendFraction()
:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// here is the same as your code
.append(DateTimeFormatter.BASIC_ISO_DATE).appendLiteral('-')
// time (hour/minute/seconds)
.appendPattern("HH:mm:ss")
// optional nanos with 9 digits (including decimal point)
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 9, 9, true)
.optionalEnd()
// optional nanos with 6 digits (including decimal point)
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 6, 6, true)
.optionalEnd()
// optional nanos with 3 digits (including decimal point)
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 3, 3, true)
.optionalEnd()
// offset
.appendOffset("+HH:mm", "Z")
// create formatter
.toFormatter();
此格式化程序的工作原理與第一個使用[]
模式創建的第一個程序完全相同。
副作用
由於@SeanVanGorder注意到in his comment,這種格式具有接收多種模式爲納秒場的副作用,但它只能如果值是相同的:
// side effect
// multiple nanos values (accepts multiple values if they're all the same)
System.out.println(OffsetDateTime.parse("20161201-10:30:45.123000.123Z", formatter)); // 2016-12-01T10:30:45.123Z
System.out.println(OffsetDateTime.parse("20161201-10:30:45.123000000.123Z", formatter)); // 2016-12-01T10:30:45.123Z
System.out.println(OffsetDateTime.parse("20161201-10:30:45.123000000.123000.123Z", formatter)); // 2016-12-01T10:30:45.123Z
以上所有行都輸出2016-12-01T10:30:45.123Z
,但請注意它們接受所有可選值(如.123000000.123
)。由於這些值是相同的,所以解析過程沒有錯誤。
如果值不同,但是,它會引發異常:
// multiple nanos values (throws exception if values are different)
System.out.println(OffsetDateTime.parse("20161201-10:30:45.123000.124Z", formatter)); // exception
如果此行爲是不希望的,唯一的選擇是創建許多不同格式器(一個用於每種情況下),並做了for
循環,直到獲得有效的解析值(非常類似於this answer)。
首先,我創建了一個方法接收的DateTimeFormatter
的列表和一個TemporalQuery
來解析字符串轉換成任何你想要的對象:
// method to parse, it receives a list of DateTimeFormatter and a TemporalQuery to convert the parsed string
public <T> T parse(String input, TemporalQuery<T> query, DateTimeFormatter... formatters) {
for (DateTimeFormatter fmt : formatters) {
try {
// try to parse
return fmt.parse(input, query);
} catch (Exception e) {}
}
// none worked, throw exception
throw new DateTimeParseException("Text '" + input + "' could not be parsed", input, 0);
}
現在你只需要創建格式化,並在使用它們parse
方法:
// alternative: have 3 different formatters
DateTimeFormatter f1 = new DateTimeFormatterBuilder()
// here is the same as your code
.append(DateTimeFormatter.BASIC_ISO_DATE).appendLiteral('-')
// time (hour/minute/seconds/3 digit nanos)
.appendPattern("HH:mm:ss.SSS")
// offset
.appendOffset("+HH:mm", "Z")
// create formatter
.toFormatter();
DateTimeFormatter f2 = new DateTimeFormatterBuilder()
// here is the same as your code
.append(DateTimeFormatter.BASIC_ISO_DATE).appendLiteral('-')
// time (hour/minute/seconds/6 digit nanos)
.appendPattern("HH:mm:ss.SSSSSS")
// offset
.appendOffset("+HH:mm", "Z")
// create formatter
.toFormatter();
DateTimeFormatter f3 = new DateTimeFormatterBuilder()
// here is the same as your code
.append(DateTimeFormatter.BASIC_ISO_DATE).appendLiteral('-')
// time (hour/minute/seconds/9 digit nanos)
.appendPattern("HH:mm:ss.SSSSSSSSS")
// offset
.appendOffset("+HH:mm", "Z")
// create formatter
.toFormatter();
// all formatters
DateTimeFormatter[] formatters = new DateTimeFormatter[] { f1, f2, f3 };
// 3 digits
System.out.println(parse("20161201-10:30:45.123Z", OffsetDateTime::from, formatters)); // 2016-12-01T10:30:45.123Z
// 6 digits
System.out.println(parse("20161201-10:30:45.123456Z", OffsetDateTime::from, formatters)); // 2016-12-01T10:30:45.123456Z
// 9 digits
System.out.println(parse("20161201-10:30:45.123456789Z", OffsetDateTime::from, formatters)); // 2016-12-01T10:30:45.123456789Z
// 4 digits (throws exception)
System.out.println(parse("20161201-10:30:45.1234Z", OffsetDateTime::from, formatters));
// java.time.format.DateTimeParseException: Text '20161201-10:30:45.1234Z' could not be parsed
// multiple values (throws exception)
System.out.println(parse("20161201-10:30:45.123000.123Z", OffsetDateTime::from, formatters));
// java.time.format.DateTimeParseException: Text '20161201-10:30:45.123000.123Z' could not be parsed
請注意,我用的方法參考OffsetDateTime::from
爲TemporalQuery
,但你可以把它改成你需要的任何查詢。
不要以爲你可以,但你爲什麼在意?接受例如什麼是錯誤的4個小數位?根據[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)完全有效。 – Andreas