如何解决scala中的无效日期格式错误?

时间:2016-01-13 13:46:37

标签: java scala datetime jodatime

我遇到了以下错误:

val formatter = ISODateTimeFormat.dateTimeParser()
scala> val date2 = "Tue Dec 29 11:11:30 IST 2015"
 date2: String = Tue Dec 29 11:11:30 IST 2015

scala> formatter.parseDateTime(date2)
java.lang.IllegalArgumentException: Invalid format: "Tue Dec 29 11:11:30 IST 2015" is malformed at "ue Dec 29 11:11:30 IST 2015"

如何解决以下错误?

2 个答案:

答案 0 :(得分:4)

我认为你的格式错误 - 使用SimpleDateFormat和a bit of googling这有效:

scala> val formatter = new java.text.SimpleDateFormat("EEE MMM d HH:mm:ss Z yyyy")
formatter: java.text.SimpleDateFormat = java.text.SimpleDateFormat@73342172

scala> formatter.parse("Tue Dec 29 11:11:30 IST 2015")
res1: java.util.Date = Tue Dec 29 09:11:30 GMT 2015

编辑:错误不要忘记我最初做的时区和年份; - )

答案 1 :(得分:3)

首先要注意的是:

您的输入不是ISO格式,并且包含时区名称(此处为:IST)。您尝试过Joda-Time,但使用的是ISO格式。这不起作用,因为 ISO格式模式与非ISO输入不匹配。反对Joda-Time的第二个原因是 Joda-Time无法解析时区名称。因此,使用理论上正确的模式的跟随方法将失败:

String input = "Tue Dec 29 11:11:30 IST 2015";
DateTimeFormatter dtf = 
  DateTimeFormat.forPattern("EEE MMM d HH:mm:ss z yyyy").withLocale(Locale.ENGLISH);
DateTime unparseable = dtf.parseDateTime(input); 
// java.lang.IllegalArgumentException: 
// Invalid format: "Tue Dec 29 11:11:30 IST 2015" is malformed at "IST 2015"

因此您只能更改库。使用(可怕的)课程SimpleDateFormat的明显候选人是:

String input = "Tue Dec 29 11:11:30 IST 2015";
String pattern = "EEE MMM d HH:mm:ss z yyyy";
SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.ENGLISH);
java.util.Date jud = sdf.parse(input);
System.out.println(jud); // Tue Dec 29 10:11:30 CET 2015 (in my local tz CET=+01:00)

好吧也不例外。但这并不意味着结果会自动纠正。结果只能通过偏移量(IST为+02:00)来解释。但这是真的???那么让我们仔细看看所涉及的时区:

TimeZone india = TimeZone.getTimeZone("Asia/Kolkata");
TimeZone israel = TimeZone.getTimeZone("Asia/Jerusalem"); 
System.out.println(israel.getDisplayName(false, TimeZone.SHORT)); // IST
System.out.println(india.getDisplayName(false, TimeZone.SHORT)); // IST

System.out.println(israel.getOffset(jud.getTime()) / 1000); // 7200 = +02:00
System.out.println(india.getOffset(jud.getTime()) / 1000); // 19800 = +05:30

这应该触发警报。时区名称(尤其是缩写,这里:IST)通常是矛盾的,表示具有不同偏移的不同时区。

所以,如果你得到了以色列的意见,那么你会感到高兴,但是如果来自印度那么结果在3:30之后就会出错。也许你的结果会匹配印度的情况而不是以色列。这取决于您当地的时区配置。所以,不要盲目相信解析的偏移量。

替代Java-8:

String input = "Tue Dec 29 11:11:30 IST 2015";
ZoneId india = ZoneId.of("Asia/Kolkata");

DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.appendPattern("EEE MMM d HH:mm:ss ");
builder.appendZoneText(TextStyle.SHORT, Collections.singleton(india)); // preferred zone
builder.appendPattern(" yyyy");
DateTimeFormatter dtf = builder.toFormatter(Locale.ENGLISH);

ZonedDateTime zdt = ZonedDateTime.parse(input, dtf);
System.out.println(zdt); // 2015-12-29T11:11:30+05:30[Asia/Kolkata]

// compare dangerous standard approach (not specifying your zone preference)
String pattern = "EEE MMM d HH:mm:ss z yyyy";
zdt = ZonedDateTime.parse(input, DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH));
System.out.println(zdt); // 2015-12-29T11:11:30+02:00[Asia/Jerusalem]

如果您指定首选时区,它会起作用,但在解析时区名称之前,您确实需要三思而后行。构建器方法可能看起来有点尴尬但由于问题的困难而无法避免。 因此,Java-8可以很好地为您提供解决方案。

顺便说一句,如果你使用严格的样式(DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH).withResolverStyle(ResolverStyle.STRICT)),那么解析器将抛出一个带有消息的异常:

  

java.time.format.DateTimeParseException:Text'Tue Dec 29 11:11:30 IST   2015'无法解析:无法从中获取ZonedDateTime   TemporalAccessor:{YearOfEra = 2015,DayOfMonth = 29,DayOfWeek = 2,   MonthOfYear = 12},ISO,亚洲/耶路撒冷解决了类型的11:11:30   java.time.format.Parsed

这条消息有点神秘,但我认为这是因为IST的矛盾名称。

如果您正在使用旧版JDK(Java 6或7)的平台上工作,那么您可能会考虑ThreetenBP ThreetenBP 的优点是可以轻松实现未来的迁移(只需更改导入语句)但不幸的是,我自己的构建器方法实验失败了(即使最新版本v1.3.1失败了 - 可能这取决于基础JDK ???):

String input = "Tue Dec 29 11:11:30 IST 2015";
ZoneId india = ZoneId.of("Asia/Kolkata");

DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.appendPattern("EEE MMM d HH:mm:ss ");
builder.appendZoneText(TextStyle.SHORT, Collections.singleton(india)); // preferred zone
builder.appendPattern(" yyyy");
DateTimeFormatter dtf = builder.toFormatter(Locale.ENGLISH);

ZonedDateTime zdt = ZonedDateTime.parse(input, dtf);
System.out.println(zdt); // 2015-12-29T11:11:30+02:00[Israel] // why???

否则,您可以尝试使用适用于Java-6或7(或更高版本)的my library Time4J 。它的工作方式类似于Java-8:

String input = "Tue Dec 29 11:11:30 IST 2015";
TZID india = ASIA.KOLKATA;

ChronoFormatter<Moment> f = ChronoFormatter.setUp(Moment.axis(),  Locale.ENGLISH)
    .addPattern("EEE MMM d HH:mm:ss ", PatternType.CLDR)
    .addShortTimezoneName(Collections.singleton(india)) // preferred zone
    .addPattern(" yyyy", PatternType.CLDR)
    .build();

 System.out.println(f.parse(input)); // 2015-12-29T05:41:30Z
 System.out.println(ZonalDateTime.parse(input, f)); // 2015-12-29T11:11:30UTC+05:30[Asia/Kolkata]

使用

的严格或智能解析器样式的错误消息
String input = "Tue Dec 29 11:11:30 IST 2015";
String pattern = "EEE MMM d HH:mm:ss z yyyy";

ChronoFormatter<Moment> f = // here smart standard style!
    ChronoFormatter.ofMomentPattern(
        pattern, PatternType.CLDR, Locale.ENGLISH, ZonalOffset.UTC);
f.parse(input);

将是:

  

在locale en的首选时区中找不到时区名称“IST”,   候选人= [亚洲/科伦坡,亚洲/耶路撒冷,亚洲/加尔各答,欧洲/都柏林]

然后你会立即看到“IST”可以与不同的时区相关联。