Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 8日期相当于Joda';具有多种解析器格式的DateTimeFormatterBuilder?_Java_Jodatime_Java Time - Fatal编程技术网

Java 8日期相当于Joda';具有多种解析器格式的DateTimeFormatterBuilder?

Java 8日期相当于Joda';具有多种解析器格式的DateTimeFormatterBuilder?,java,jodatime,java-time,Java,Jodatime,Java Time,我目前有一个Joda日期解析器,它使用DateTimeFormatterBuilder,可以接收六种不同的日期格式 我正在迁移到Java8的日期例程,但没有看到等效的 我如何使用Java8日期执行类似的操作 DateTimeParser[] parsers = { DateTimeFormat.forPattern( "yyyy/MM/dd HH:mm:ss.SSSSSS" ).getParser() , DateTimeFormat.forPattern( "yyyy-MM-

我目前有一个Joda日期解析器,它使用DateTimeFormatterBuilder,可以接收六种不同的日期格式

我正在迁移到Java8的日期例程,但没有看到等效的

我如何使用Java8日期执行类似的操作

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()

当代码需要以可配置的方式接受不同的模式时,使用streams迭代@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
yyy-MM-dd HH:MM:ss[.SSS]
ddmmmyyyyy: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):


您可能会发现性能严重下降,特别是如果您计划通过异常处理实现替换的话。根据我自己的测试,乔达的时间更快。另请参见此。如果区域设置也不同,则此代码将不起作用。请注意,您不能将其用于格式化,只能用于解析。使用这种格式化程序进行格式化时,您将获得所有格式。我猜如果你想要一些可选格式和一个“默认”显示,你必须使用两个不同的
DateTimeFormatter
实例——一个用于解析的可选格式,另一个仅用于显示的默认格式不起作用,但“[yyyyMMdd'T'hhmmsz]”应该注意,模式的顺序很重要,它们应该是从最长到最短,从最严格到最不严格。这将不起作用:
DateTimeFormatter formatter=DateTimeFormatter.of模式(“+”[yyy-MM-dd]“+”[yyy-MM-dd HH:MM:ss]“+”[dd/MM/yyyy]“+”[dd/MM/yyyy HH:MM:ss]”
这是正确的:
DateTimeFormatter.of模式(“+”[yyyy-MM-dd-HH:MM:ss]“+”[dd/MM/yyyy-HH:MM:ss]“+”[yyyy-MM-dd]“+”[dd/MM/yyyy]”)
我没有让它与多个append一起工作。我创建了一个DateTimeFormatter列表和一个带有try/catch的循环。@Avec try-catch应该用于处理异常,而不是用于预期的输入。但是您是对的,建议的代码不正确。只能将多个格式化程序与Appender一起使用DateTimeFormatterBuilder的可选方法。
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();