有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使用Scala在DateTimeFormatter中传递多个日期格式

我有三种日期格式:YYYY-MM-DD、ddmmyyy、mmddyyy这是我在Spark中传递日期格式进行解析的方式

scala> val formatter = DateTimeFormatter.ofPattern("[MMddyyyy][yyyy-MM-dd][yyyyMMdd]")
formatter: java.time.format.DateTimeFormatter = [Value(MonthOfYear,2)Value(DayOfMonth,2)Value(YearOfEra,4,19,EXCEEDS_PAD)][Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)][Value(YearOfEra,4,19,EXCEEDS_PAD)Value(MonthOfYear,2)Value(DayOfMonth,2)]

对于格式MMddyyyy,它正在工作

scala> LocalDate.parse("10062019",formatter)
res2: java.time.LocalDate = 2019-10-06

对于格式yyyyMMdd,它正在工作

scala> LocalDate.parse("2019-06-20",formatter)
res3: java.time.LocalDate = 2019-06-20

对于格式yyyyMMdd,它给了我一个错误

scala> LocalDate.parse("20190529",formatter)
java.time.format.DateTimeParseException: Text '20190529' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 20
  at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)
  at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855)
  at java.time.LocalDate.parse(LocalDate.java:400)
  ... 66 elided
Caused by: java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 20
  at java.time.temporal.ValueRange.checkValidIntValue(ValueRange.java:330)
  at java.time.temporal.ChronoField.checkValidIntValue(ChronoField.java:722)
  at java.time.chrono.IsoChronology.resolveYMD(IsoChronology.java:550)
  at java.time.chrono.IsoChronology.resolveYMD(IsoChronology.java:123)
  at java.time.chrono.AbstractChronology.resolveDate(AbstractChronology.java:472)
  at java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:492)
  at java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:123)
  at java.time.format.Parsed.resolveDateFields(Parsed.java:351)
  at java.time.format.Parsed.resolveFields(Parsed.java:257)
  at java.time.format.Parsed.resolve(Parsed.java:244)
  at java.time.format.DateTimeParseContext.toResolved(DateTimeParseContext.java:331)
  at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1955)
  at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
  ... 67 more

如果我通过了2个格式yyyyMMdd,yyyy MM dd,它工作正常

    scala> val formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyyMMdd]") 
scala> LocalDate.parse("20190529",formatter)
res5: java.time.LocalDate = 2019-05-29

scala> LocalDate.parse("2019-06-20",formatter)
res6: java.time.LocalDate = 2019-06-20

与yyyy MM dd、mmddyyy日期格式相同

   scala> val formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd][MMddyyyy]")

    scala> LocalDate.parse("10062019",formatter)
    res7: java.time.LocalDate = 2019-10-06

    scala> LocalDate.parse("2019-06-20",formatter)
    res8: java.time.LocalDate = 2019-06-20

有没有办法让我通过三种不同的格式


共 (3) 个答案

  1. # 1 楼答案

    您不能同时在格式化程序[yyyyymmdd]和[MMddyyyy]中输入。 我的想法是规范化,这样您就有了[yyyy-MM-dd]和[MM-dd-yyyy],而不是3种格式

    希望这有帮助

    编辑:

    如果你没有机会,你可以做这样的事情,但它不是很漂亮

    val formatter1 = DateTimeFormatter.ofPattern("[yyyy-MM-dd][MMddyyyy]")
    val formatter2 = DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyyMMdd]")
    
    val time = "20190529"
    
    if (time.matches("2+\\d*")) LocalDate.parse(time,formatter2) else 
    LocalDate.parse(time,formatter1)
    
  2. # 2 楼答案

    Java自己的^{}可以在不依赖异常处理的情况下处理它。从文件中:

    The formatter will format if data is available for all the fields contained within it. The formatter will parse if the string matches, otherwise no error is returned.

    这意味着您不必处理多个例外情况

    下面是一个来自真实代码库的示例,我必须在其中执行此处理:

    def dtf: DateTimeFormatter =
      new DateTimeFormatterBuilder()
       .appendOptional(DateTimeFormatter.ofPattern("dd/MM/yy"))
       .appendOptional(DateTimeFormatter.ofPattern("dd/MM/yyyy"))
       .toFormatter()
    

    下面是两个单元测试(在ScalaTest中)演示了该用法:

    "Short form is parsed" in {
      assert(LocalDate.parse("28/08/20", dtf) == LocalDate.of(2020, 8, 28))
    }
    "Long form is parsed" in {
      assert(LocalDate.parse("02/10/2020", dtf) == LocalDate.of(2020, 10, 2))
    }
    
  3. # 3 楼答案

    只有问题中的信息,这是不可能的。字符串10111213可以表示1011年12月13日或1213年10月11日。但是,假设您的日期总是在1300年之后,您是幸运的,因为此时字符串的YYYY部分不能被解析为MMDD,因为月份将是13或更大,也就是说,无效。您可以使用它来决定使用哪种格式是正确的

    我将使用三个格式化程序,并依次尝试它们:

    private static final DateTimeFormatter[] DATE_FORMATTERS = {
            DateTimeFormatter.ofPattern("uuuuMMdd"),
            DateTimeFormatter.ofPattern("MMdduuuu"),
            DateTimeFormatter.ofPattern("uuuu-MM-dd")
    };
    

    有了这些,你就可以:

        String dateString = "20190529";
    
        LocalDate result = null;
        for (DateTimeFormatter df : DATE_FORMATTERS) {
            try {
                result = LocalDate.parse(dateString, df);
                break;
            } catch (DateTimeParseException dtpe) {
                // Ignore; try next formatter
            }
        }
        System.out.println("" + dateString + " was parsed to " + result);
    

    输出为:

    20190529 was parsed to 2019-05-29

    让我们也试试其他两种格式:

    10062019 was parsed to 2019-10-06

    2019-06-20 was parsed to 2019-06-20

    我建议您添加一个空检查,以捕获任何不可解析的日期字符串,并在解析的日期上添加一个范围检查,以便10111213不会作为有效日期漏掉。例如:

        if (result == null) {
            System.out.println(dateString + " could not be parsed");
        }
        else if (result.isBefore(LocalDate.now(ZoneId.of("Asia/Aden")))) {
            System.out.println("Date should be in the future, was " + result);
        }
    

    PS我假设你问题的第一句有一个拼写错误:

    I have three date formats: YYYY-MM-DD, DDMMYYYY, MMDDYYYY this is how I pass date format in Spark to parse.

    中间的格式应该是YYYYMMDD(否则就没有机会了)