我有三种日期格式:YYYY-MM-DD,DDMMYYYY,MMDDYYYY,这就是我在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
有什么办法可以传递三种不同的格式?
答案 0 :(得分:0)
您不能同时在格式化程序[yyyyMMdd]和[MMddyyyyy]中使用。 我的想法是进行归一化,因此您有[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)
答案 1 :(得分:0)
仅使用问题中的信息,这是不可能的。字符串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被解析为2019-05-29
我们也尝试其他两种格式:
10062019已解析为2019-10-06
2019-06-20被解析为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,我想在您的问题的第一句中输入错字:
我有三种日期格式:YYYY-MM-DD,DDMMYYYY,MMDDYYYY 我在Spark中传递日期格式进行解析。
中间格式应为YYYYMMDD(否则您将没有机会)。
答案 2 :(得分:0)
Java自己的DateTimeFormatterBuilder#appendOptional
可以在不依赖异常处理的情况下处理它。从文档中:
如果数据可用于其中包含的所有字段,则格式化程序将进行格式化。格式化程序将解析字符串是否匹配,否则不返回错误。
这意味着您将不必处理多个例外情况。
这是一个来自真实代码库的示例,在该示例中,我必须进行以下处理:
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))
}