Liu*_* E. 4 java time parsing java-time
我需要创建用于解析时间戳的格式化程序,并带有可选的毫秒,微米或毫微秒的分数。
例如,根据我的需要,我看到了以下机会:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.BASIC_ISO_DATE)
.appendLiteral('-')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendOffset("+HH:mm", "Z")
.toFormatter();
Run Code Online (Sandbox Code Playgroud)
或者也可以使用appendFraction(field, minWidth, maxWidth, decimalPoint)。
但是,在这些情况下,可以解析任意数量的小数(最多9个或maxWidth)的时间戳。如何实现我们只能在逗号后解析(可选)仅3、6或9个数字?
应该可以解析以下时间部分:
HH:mm:ss.SSSHH:mm:ss.SSSSSSHH:mm:ss.SSSSSSSSS但无法解析:HH:mm:ss.SSSS。
小智 6
您可以使用可选部分模式(由分隔[]),并创建3个可选部分:1个代表9位数字,另一个代表6位数字,另一个代表3位数字。
根据DateTimeFormatterBuilderdocs,您可以使用S模式(相当于NANO_OF_SECOND字段):
Pattern Count Equivalent builder methods
------- ----- --------------------------
S..S 1..n appendFraction(ChronoField.NANO_OF_SECOND, n, n, false)
Run Code Online (Sandbox Code Playgroud)
在旧的API(SimpleDateFormat)中,S模式是毫秒,但是在新的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();
Run Code Online (Sandbox Code Playgroud)
一些测试:
// 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));
Run Code Online (Sandbox Code Playgroud)
输出为:
2016-12-01T10:30:45.123Z
2016-12-01T10:30:45.123456Z
2016-12-01T10:30:45.123456789Z
线程“ main”中的异常java.time.format.DateTimeParseException:文本'20161201-10: 30:45.1234Z'无法在索引21处解析
笔记:
这种情况下DateTimeFormatter是不适合的格式,因为它打印所有可选节(所以纳秒将被打印出来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
Run Code Online (Sandbox Code Playgroud)因此,如果您想以其他格式显示日期,请考虑创建另一个DateTimeFormatter。
在您的代码中使用DateTimeFormatter.ISO_LOCAL_TIME。根据javadoc,在此格式化程序中,秒是可选的。如果您希望具有相同的行为,只需将时间模式更改为:
// time (hour/minute) with optional seconds
.appendPattern("HH:mm[:ss]")
Run Code Online (Sandbox Code Playgroud)该[]模式是创建可选节的不错捷径,但是您也可以使用optionalStart()with 创建它们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();
Run Code Online (Sandbox Code Playgroud)此格式化程序的工作方式与使用[]pattern 创建的第一个格式化程序完全相同。
就像@SeanVanGorder 在他的评论中注意到的那样,此格式化程序具有接受纳秒字段的多种模式的副作用,但仅在值相同时才有效:
// 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
Run Code Online (Sandbox Code Playgroud)
输出以上的所有行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
Run Code Online (Sandbox Code Playgroud)
如果不需要这种行为,唯一的选择是创建许多不同的格式化程序(每种情况一个),并进行for循环直到获得有效的解析值(非常类似于此答案)。
首先,我创建了一个方法,该方法接收的列表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);
}
Run Code Online (Sandbox Code Playgroud)
现在,您只需要创建格式化程序并在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
Run Code Online (Sandbox Code Playgroud)
请注意,我将方法引用OffsetDateTime::from用作TemporalQuery,但您可以将其更改为所需的任何查询。
DateTimeFormatter仅支持宽度范围,因此对于单个实例来说这是不可能的。您可以使用.appendFraction(NANO_OF_SECOND, #, #, true)# 为 3、6 或 9 来创建 3 个单独的格式化程序。然后按顺序尝试它们,忽略任何一个,DateTimeParseException直到最后一个:
private static TemporalAccessor parse(String text) {
try {
return formatter3.parse(text);
} catch (DateTimeParseException e) {
// ignore
}
try {
return formatter6.parse(text);
} catch (DateTimeParseException e) {
// ignore
}
return formatter9.parse(text); // let this one throw
}
Run Code Online (Sandbox Code Playgroud)
另一种选择是首先使用正则表达式检查输入,例如text.matches("[^.]+(.+\\.(\\d{3}|\\d{6}|\\d{9})\\b.*)?").
| 归档时间: |
|
| 查看次数: |
6732 次 |
| 最近记录: |