java 时间回退_java.time DateTimeFormatter使用灵活的回退值进行解析

如果找不到该字段,parseDefaulting将设置该字段的值,即使对于不在该模式中的字段也是如此,因此您最终可能会遇到解析结果中存在年份和年份的情况.

对我来说,最简单的解决方案是在评论中建议的:检查输入是否包含带有正则表达式的年份(或看起来像一个数字的东西,例如4位数),或检查输入的长度,然后创建格式化程序相应的(没有默认值).例子:

if (input_without_year) {

LocalDate d = MonthDay

.parse("12/06", DateTimeFormatter.ofPattern("MM/dd"))

.atYear(1970);

} else {

// use formatter with year, without default values

}

但如果你想要一个通用的解决方案,我担心它会更复杂.另一种方法是解析输入并检查其中是否有任何年份字段.如果没有,那么我们将其更改为返回年份的默认值:

public static TemporalAccessor parse(String pattern, String input) {

DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern, Locale.ROOT);

final TemporalAccessor parsed = fmt.parse(input);

// check year and year of era

boolean hasYear = parsed.isSupported(ChronoField.YEAR);

boolean hasYearEra = parsed.isSupported(ChronoField.YEAR_OF_ERA);

if (!hasYear && !hasYearEra) {

// parsed value doesn't have any year field

// return another TemporalAccessor with default value for year

// using year 1970 - change it to Year.now().getValue() for current year

return withYear(parsed, 1970); // see this method's code below

}

return parsed;

}

首先,我们解析并获取包含所有已解析字段的TemporalAccessor.然后我们检查它是否有年份或年份字段.如果它没有任何这些,我们创建另一个具有年份默认值的TemporalAccessor.

在上面的代码中,我使用1970,但您可以将其更改为您需要的任何内容. withYear方法有一些重要的细节需要注意:

>我假设输入总是有月和日.如果不是这种情况,您可以更改下面的代码以使用它们的默认值

>要检查字段是否存在,请使用isSupported方法

withYear方法如下:

public static TemporalAccessor withYear(TemporalAccessor t, long year) {

return new TemporalAccessor() {

@Override

public boolean isSupported(TemporalField field) {

// epoch day is used by LocalDate.from

if (field == ChronoField.YEAR_OF_ERA || field == ChronoField.EPOCH_DAY) {

return true;

} else {

return t.isSupported(field);

}

}

@Override

public long getLong(TemporalField field) {

if (field == ChronoField.YEAR_OF_ERA) {

return year;

// epoch day is used by LocalDate.from

} else if (field == ChronoField.EPOCH_DAY) {

// Assuming the input always have month and day

// If that's not the case, you can change the code to use default values as well,

// and use MonthDay.of(month, day)

return MonthDay.from(t).atYear((int) year).toEpochDay();

} else {

return t.getLong(field);

}

}

};

}

现在这个工作:

System.out.println(LocalDate.from(parse("MM/dd", "12/06"))); // 1970-12-06

System.out.println(LocalDate.from(parse("uuuu/MM/dd", "2018/12/06"))); // 2018-12-06

System.out.println(LocalDate.from(parse("yyyy/MM/dd", "2018/12/06"))); // 2018-12-06

但我仍然认为第一种解决方案更简单.

替代

假设您总是创建LocalDate,另一种方法是使用parseBest:

public static LocalDate parseLocalDate(String pattern, String input) {

DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern, Locale.ROOT);

// try to create a LocalDate first

// if not possible, try to create a MonthDay

TemporalAccessor parsed = fmt.parseBest(input, LocalDate::from, MonthDay::from);

LocalDate dt = null;

// check which type was created by the parser

if (parsed instanceof LocalDate) {

dt = (LocalDate) parsed;

} else if (parsed instanceof MonthDay) {

// using year 1970 - change it to Year.now().getValue() for current year

dt = ((MonthDay) parsed).atYear(1970);

} // else etc... - do as many checkings you need to handle all possible cases

return dt;

}

然后我检查返回的类型并采取相应的行动.您可以展开它以检查所需的类型,也可以编写自己的TemporalQuery来处理特定情况.

有了这个,所有案例也有效:

System.out.println(parseLocalDate("MM/dd", "12/06")); // 1970-12-06

System.out.println(parseLocalDate("uuuu/MM/dd", "2018/12/06")); // 2018-12-06

System.out.println(parseLocalDate("yyyy/MM/dd", "2018/12/06")); // 2018-12-06

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值