Java 8 相当于 Joda 的具有多种解析器格式的 DateTimeFormatterBuilder 的日期?
Java 8 Date equivalent to Joda's DateTimeFormatterBuilder with multiple parser formats?
我目前有一个 Joda 日期解析器,它使用 DateTimeFormatterBuilder,我可能会收到六种不同的日期格式。
我正在迁移到 Java 8 的日期例程,但没有看到等效项。
如何使用 Java 8 个日期来做这样的事情?
DateTimeParser[] parsers = {
DateTimeFormat.forPattern( "yyyy/MM/dd HH:mm:ss.SSSSSS" ).getParser() ,
DateTimeFormat.forPattern( "yyyy-MM-dd HH:mm:ss" ).getParser() ,
DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSS Z" ).getParser() ,
DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSS" ).getParser() ,
DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSSSSS" ).getParser() ,
DateTimeFormat.forPattern( "yyyy-MM-dd HH:mm:ss.SSS" ).getParser()
};
DateTimeFormatter dateTimeFormatterInput = new DateTimeFormatterBuilder()
.append( null, parsers ).toFormatter();
没有直接的工具可以执行此操作,但您可以使用可选部分。可选部分括在方括号 []
内。这允许要解析的字符串的整个部分丢失。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(""
+ "[yyyy/MM/dd HH:mm:ss.SSSSSS]"
+ "[yyyy-MM-dd HH:mm:ss[.SSS]]"
+ "[ddMMMyyyy:HH:mm:ss.SSS[ Z]]"
);
此格式化程序为您拥有的三个主要模式定义了 3 个重要的可选部分。它们每个都在其自己的可选部分中。
工作演示代码:
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(""
+ "[yyyy/MM/dd HH:mm:ss.SSSSSS]"
+ "[yyyy-MM-dd HH:mm:ss[.SSS]]"
+ "[ddMMMyyyy:HH:mm:ss.SSS[ Z]]"
, Locale.ENGLISH);
System.out.println(LocalDateTime.parse("2016/03/23 22:00:00.256145", formatter));
System.out.println(LocalDateTime.parse("2016-03-23 22:00:00", formatter));
System.out.println(LocalDateTime.parse("2016-03-23 22:00:00.123", formatter));
System.out.println(LocalDateTime.parse("23Mar2016:22:00:00.123", formatter));
System.out.println(LocalDateTime.parse("23Mar2016:22:00:00.123 -0800", formatter));
}
作为 Tunaki 的替代答案,您还可以使用 DateTimeFormatterBuilder:
DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder()
.appendPattern("[yyyy]")
.appendPattern("[M/d/yyyy]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter()
当代码需要以可配置的方式接受不同的模式时,使用流迭代@Tunaki 的解决方案:
DateTimeFormatter dateTimeFormatter = dateFormats.stream()
.map(DateTimeFormatter::ofPattern)
.reduce(new DateTimeFormatterBuilder(),
DateTimeFormatterBuilder::appendOptional,
(f1, f2) -> f1.append(f2.toFormatter()))
.toFormatter();
在这种情况下,我不关心减速器的组合器部分,但我在签名中需要它,所以我使组合器正确。
如果将上述模式(yyyy/MM/dd HH:mm:ss.SSSSSS
、yyyy-MM-dd HH:mm:ss[.SSS]
、ddMMMyyyy:HH:mm:ss.SSS[ Z]
)馈送到流中,此代码实际上等效于:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSSSSS")
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]"
.appendOptional(DateTimeFormatter.ofPattern("ddMMMyyyy:HH:mm:ss.SSS[ Z]")
.toFormatter();
根据@Brice 的回答,我编写了以下方法,最适合我
private LocalDate parseDate(String date) {
DateTimeFormatter yearFormat = new DateTimeFormatterBuilder()
.appendPattern("yyyy")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter();
DateTimeFormatter yearAndMonthFormat = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM")
.parseDefaulting(ChronoField.DAY_OF_MONTH,1)
.toFormatter();
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormatter.ISO_DATE)
.appendOptional(yearAndMonthFormat)
.appendOptional(yearFormat)
.toFormatter();
LocalDate result = LocalDate.parse(date, formatter);
return result;
}
注意添加到最后一个的可选格式化程序的顺序。倒序只适用于 "yyyy" 类型的日期。建议的顺序允许我解析以下所有内容:
- 2014
- 2014-10
- 2014-03-15
只是为有人会有类似用例的情况添加。
这是我最终想到的。它处理三种不同的主要格式,每种格式都有多个较小的格式差异(例如允许 - 或 / 定界符)以及处理可变数量的微秒(从 0 到 6):
private static final DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern( "[ddMMMyyyy:HH:mm:ss" )
.optionalStart()
.appendFraction( ChronoField.MICRO_OF_SECOND , 1 , 6 , true )
.optionalEnd()
.appendPattern( "[ ][Z][X]]" )
.appendPattern( "[yyyy[-][/]MM[-][/]dd['T'][ ]HH:mm[:][.]ss" )
.optionalStart()
.appendFraction( ChronoField.MICRO_OF_SECOND , 1 , 6 , true )
.optionalEnd()
.appendPattern( "[Z][X]]" )
.appendPattern( "[EEE, dd MMM yyyy HH:mm:ss zzz]" )
.toFormatter();
我目前有一个 Joda 日期解析器,它使用 DateTimeFormatterBuilder,我可能会收到六种不同的日期格式。
我正在迁移到 Java 8 的日期例程,但没有看到等效项。
如何使用 Java 8 个日期来做这样的事情?
DateTimeParser[] parsers = {
DateTimeFormat.forPattern( "yyyy/MM/dd HH:mm:ss.SSSSSS" ).getParser() ,
DateTimeFormat.forPattern( "yyyy-MM-dd HH:mm:ss" ).getParser() ,
DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSS Z" ).getParser() ,
DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSS" ).getParser() ,
DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSSSSS" ).getParser() ,
DateTimeFormat.forPattern( "yyyy-MM-dd HH:mm:ss.SSS" ).getParser()
};
DateTimeFormatter dateTimeFormatterInput = new DateTimeFormatterBuilder()
.append( null, parsers ).toFormatter();
没有直接的工具可以执行此操作,但您可以使用可选部分。可选部分括在方括号 []
内。这允许要解析的字符串的整个部分丢失。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(""
+ "[yyyy/MM/dd HH:mm:ss.SSSSSS]"
+ "[yyyy-MM-dd HH:mm:ss[.SSS]]"
+ "[ddMMMyyyy:HH:mm:ss.SSS[ Z]]"
);
此格式化程序为您拥有的三个主要模式定义了 3 个重要的可选部分。它们每个都在其自己的可选部分中。
工作演示代码:
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(""
+ "[yyyy/MM/dd HH:mm:ss.SSSSSS]"
+ "[yyyy-MM-dd HH:mm:ss[.SSS]]"
+ "[ddMMMyyyy:HH:mm:ss.SSS[ Z]]"
, Locale.ENGLISH);
System.out.println(LocalDateTime.parse("2016/03/23 22:00:00.256145", formatter));
System.out.println(LocalDateTime.parse("2016-03-23 22:00:00", formatter));
System.out.println(LocalDateTime.parse("2016-03-23 22:00:00.123", formatter));
System.out.println(LocalDateTime.parse("23Mar2016:22:00:00.123", formatter));
System.out.println(LocalDateTime.parse("23Mar2016:22:00:00.123 -0800", formatter));
}
作为 Tunaki 的替代答案,您还可以使用 DateTimeFormatterBuilder:
DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder()
.appendPattern("[yyyy]")
.appendPattern("[M/d/yyyy]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter()
当代码需要以可配置的方式接受不同的模式时,使用流迭代@Tunaki 的解决方案:
DateTimeFormatter dateTimeFormatter = dateFormats.stream()
.map(DateTimeFormatter::ofPattern)
.reduce(new DateTimeFormatterBuilder(),
DateTimeFormatterBuilder::appendOptional,
(f1, f2) -> f1.append(f2.toFormatter()))
.toFormatter();
在这种情况下,我不关心减速器的组合器部分,但我在签名中需要它,所以我使组合器正确。
如果将上述模式(yyyy/MM/dd HH:mm:ss.SSSSSS
、yyyy-MM-dd HH:mm:ss[.SSS]
、ddMMMyyyy:HH:mm:ss.SSS[ Z]
)馈送到流中,此代码实际上等效于:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSSSSS")
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]"
.appendOptional(DateTimeFormatter.ofPattern("ddMMMyyyy:HH:mm:ss.SSS[ Z]")
.toFormatter();
根据@Brice 的回答,我编写了以下方法,最适合我
private LocalDate parseDate(String date) {
DateTimeFormatter yearFormat = new DateTimeFormatterBuilder()
.appendPattern("yyyy")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter();
DateTimeFormatter yearAndMonthFormat = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM")
.parseDefaulting(ChronoField.DAY_OF_MONTH,1)
.toFormatter();
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormatter.ISO_DATE)
.appendOptional(yearAndMonthFormat)
.appendOptional(yearFormat)
.toFormatter();
LocalDate result = LocalDate.parse(date, formatter);
return result;
}
注意添加到最后一个的可选格式化程序的顺序。倒序只适用于 "yyyy" 类型的日期。建议的顺序允许我解析以下所有内容:
- 2014
- 2014-10
- 2014-03-15
只是为有人会有类似用例的情况添加。
这是我最终想到的。它处理三种不同的主要格式,每种格式都有多个较小的格式差异(例如允许 - 或 / 定界符)以及处理可变数量的微秒(从 0 到 6):
private static final DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern( "[ddMMMyyyy:HH:mm:ss" )
.optionalStart()
.appendFraction( ChronoField.MICRO_OF_SECOND , 1 , 6 , true )
.optionalEnd()
.appendPattern( "[ ][Z][X]]" )
.appendPattern( "[yyyy[-][/]MM[-][/]dd['T'][ ]HH:mm[:][.]ss" )
.optionalStart()
.appendFraction( ChronoField.MICRO_OF_SECOND , 1 , 6 , true )
.optionalEnd()
.appendPattern( "[Z][X]]" )
.appendPattern( "[EEE, dd MMM yyyy HH:mm:ss zzz]" )
.toFormatter();