编程语言
首页 > 编程语言> > java – 如何解析只有4位数的年份

java – 如何解析只有4位数的年份

作者:互联网

我正在使用Joda-Time解析这样的年代:

private DateTime attemptParse(String pattern, String date) {
        DateTimeFormatter parser = DateTimeFormat.forPattern(pattern).withLocale(Locale.ENGLISH);
        DateTime parsedDateTime = parser.parseLocalDateTime(date).toDateTime(WET);
        return parsedDateTime;
    }

我正在尝试解析多种格式:“yyyy-MM-dd”,“yyyy-MMM-dd”,“yyyy MMM dd-dd”,“yyyy MMM”,(等),“yyyy”.当一个人不工作时,我会尝试下一个.

当字符串确实只有4位数时(例如:“2016”),它就像一个魅力.问题是我有时会收到这样的信息:“201400”.而Joda-Time将其与“yyyy”模式相匹配,并返回201400年的日期.

我想避免丑陋如果检查年份> 9999.使用Joda-Time有什么办法吗?

解决方法:

要解析多种格式,您可以创建许多DateTimeParser实例并将所有实例连接在一个格式化程序中(而不是一个接一个地尝试).

这将需要一个DateTimeFormatterBuilder,它也将用于在输入中强制执行特定数量的数字(遗憾的是,没有办法像使用DateTimeFormat.forPattern()那样强制执行特定数量的数字).

首先,您创建了许多org.joda.time.format.DateTimeParser实例(每个可能的模式一个):

// only yyyy
DateTimeParser p1 = new DateTimeFormatterBuilder()
    // year with exactly 4 digits
    .appendYear(4, 4).toParser();
// yyyy-MM-dd
DateTimeParser p2 = new DateTimeFormatterBuilder()
    // year with exactly 4 digits
    .appendYear(4, 4)
    // rest of the pattern
    .appendPattern("-MM-dd").toParser();
// yyyy MMM
DateTimeParser p3 = new DateTimeFormatterBuilder()
    // year with exactly 4 digits
    .appendYear(4, 4)
    // rest of the pattern
    .appendPattern(" MMM").toParser();

然后创建一个包含所有这些模式的数组,并用它创建一个DateTimeFormatter:

// create array with all the possible patterns
DateTimeParser[] possiblePatterns = new DateTimeParser[] { p1, p2, p3 };

DateTimeFormatter parser = new DateTimeFormatterBuilder()
    // append all the possible patterns
    .append(null, possiblePatterns)
    // use the locale you want (in case of month names and other locale sensitive data)
    .toFormatter().withLocale(Locale.ENGLISH);

我也使用了Locale.ENGLISH(因为你也在你的问题代码中使用它).此区域设置表示月份名称将为英语(因此MMM可以解析Jan和Sep等值).有了这个,你可以解析输入:

System.out.println(parser.parseLocalDateTime("2014")); // OK
System.out.println(parser.parseLocalDateTime("201400")); // exception
System.out.println(parser.parseLocalDateTime("2014-10-10")); // OK
System.out.println(parser.parseLocalDateTime("201400-10-10")); // exception
System.out.println(parser.parseLocalDateTime("2014 Jul")); // OK
System.out.println(parser.parseLocalDateTime("201400 Jul")); // exception

当年是2014年,代码工作正常.当它是201400时,它会抛出一个java.lang.IllegalArgumentException,例如:

java.lang.IllegalArgumentException: Invalid format: “201400” is malformed at “00”

DateTimeFormatter是不可变且线程安全的,因此每次调用验证方法时都不需要创建它.您可以在方法之外创建它(例如在静态最终字段中).

这比每次执行验证时创建一个格式化程序更好,并在发生异常时转到下一个格式化程序.创建的格式化程序已经在内部执行,转到下一个模式,直到找到一个有效的模式(或者如果所有模式都失败则抛出异常).

Java新的日期/时间API

Joda-Time处于维护模式,正在被新的API取代,因此我不建议使用它来启动新项目.即使在joda’s website它也说:“请注意,Joda-Time被认为是一个很大程度上已经完成的项目.没有计划进行重大改进.如果使用Java SE 8,请迁移到java.time(JSR-310).”

如果您不能(或不想)从Joda-Time迁移到新API,则可以忽略此部分.

如果您使用的是Java 8,请考虑使用new java.time API.它更容易,less bugged and less error-prone than the old APIs.

如果您使用的是Java 6或7,则可以使用ThreeTen Backport,它是Java 8新日期/时间类的优秀后端.而对于Android,你还需要ThreeTenABP(更多关于如何使用它here).

以下代码适用于两者.
唯一的区别是包名称(在Java 8中是java.time,在ThreeTen Backport(或Android的ThreeTenABP)中是org.threeten.bp),但类和方法名称是相同的.

这个新API比以前的API严格得多,因此格式化程序只能使用确切的位数(请注意,某些类与Joda-Time非常相似):

// 4 digits in year
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy", Locale.ENGLISH);
fmt.parse("2014"); // OK
fmt.parse("201400"); // exception
fmt.parse("201"); // exception

此代码适用于2014年,但是对于201400或201(或任何其他没有正好4位数的值),它会引发异常:

java.time.format.DateTimeParseException: Text ‘201400’ could not be parsed at index 0

有了这个,您的验证代码可以使用字符串数组.

只有一个细节:当解析为日期时,Joda-Time在输入没有某些字段时设置默认值(例如月份变为1月,日变为1,小时/分钟/秒设置为零等).

如果您只是验证输入,那么您不需要返回任何内容.只需检查是否抛出异常,您就会知道输入是否有效.

但是,如果您只需要年份值,则可以使用Year class

DateTimeFormatter parser = DateTimeFormatter.ofPattern("yyyy", Locale.ENGLISH);
System.out.println(Year.parse("2014", parser)); // ok
System.out.println(Year.parse("201400", parser)); // exception

如果您希望年份值为int:

Year year = Year.parse("2014", parser);
int yearValue = year.getValue(); // 2014

但是如果你想获得一个日期对象,你需要手动设置默认值 – 新API非常严格,不要自动设置这些值.在这种情况下,您必须使用DateTimeFormatterBuilder设置默认值.

我还将它解析为LocalDateTime,就像示例:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // string pattern
    .appendPattern("yyyy")
    // default month is January
    .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
    // default day is 1
    .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
    // default hour is zero
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    // default minute is zero
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    // set locale
    .toFormatter(Locale.ENGLISH);
// create LocalDateTime
System.out.println(LocalDateTime.parse("2014", fmt)); // 2014-01-01T00:00
System.out.println(LocalDateTime.parse("201400", fmt)); // exception

您可以选择所需的任何值作为字段的默认值,并使用任何new available date types.

标签:java,jodatime,date-parsing
来源: https://codeday.me/bug/20190622/1264154.html