如何使用Java 8时间API将两位数年份转换为全年

时间:2018-06-06 12:01:26

标签: java jodatime java-time 2-digit-year

我希望从我的项目中删除Joda-Time库。

我正在尝试将两位数年份转换为全年。 Joda-Time的以下代码可以实现此目的。以下是joda-time的以下代码

DateTimeFormatter TWO_YEAR_FORMATTER = DateTimeFormat.forPattern("yy");
int year = LocalDate.parse("99"", TWO_YEAR_FORMATTER).getYear();
System.out.println(year);

产出:1999

这是我期望的输出,这在我的情况下是有意义的。但是,当我使用java.time API尝试相同的过程时,它会生成DatetimeParseException。以下是java.time API的以下代码:

DateTimeFormatter TWO_YEAR_FORMATTER = DateTimeFormatter.ofPattern("yy");
int year = LocalDate.parse("99", TWO_YEAR_FORMATTER).getYear();
System.out.println(year);

堆栈跟踪:

Exception in thread "main" java.time.format.DateTimeParseException: Text '99' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {Year=2099},ISO of type java.time.format.Parsed
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.LocalDate.parse(LocalDate.java:428)
    at scratch.main(scratch.java:10)
Caused by: java.time.DateTimeException: Unable to obtain LocalDate from TemporalAccessor: {Year=2099},ISO of type java.time.format.Parsed
    at java.base/java.time.LocalDate.from(LocalDate.java:396)
    at java.base/java.time.format.Parsed.query(Parsed.java:235)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    ... 2 more

我没有看到堆栈跟踪的原因。如果有人可以帮助我理解以下场景,并解释如何使用Java 8时间API将两位数转换为全年,那将是很好的。

5 个答案:

答案 0 :(得分:7)

问题在于,您无法将自己的一年解析为LocalDate。 LocalDate需要更多信息。

您可以使用格式化程序的{"Response":{"@xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance", "@xmlns:xsd":"http://www.w3.org/2001/XMLSchema", "ReturnCode":"429", "ReturnMessage":"Invalid Coupon offer code"}} 方法,它会为您提供TemporalAccessor,然后从中获取年份字段:

parse

解决两者之间的差异:这是两个不同的API。是的,它们非常相似,int year = TWO_YEAR_FORMATTER.parse("99").get(ChronoField.YEAR); System.out.println(year); 软件包是根据JodaTime的设计决定通知的,但它从来没有打算成为它的直接替代品。

如果您想更改枢轴年份,请参阅this answer(默认情况下' 99'将解析为2099而非1999年)。

答案 1 :(得分:5)

您无法创建LocalDate,因为您提供的String未提供填写所有必填字段所需的信息。

您可以创建Year

Year parsed = Year.parse("99", TWO_YEAR_FORMATTER);
int year = parsed.getValue();

答案 2 :(得分:5)

为什么它不起作用

java.time不像Joda-Time那样提供月份和日期的默认值。消息说它不能单独从一年获得LocalDate,或相反,它不会在月和日中丢失(但是,您可以提供自己的默认值,如Mikhail Kholodkov’s answer中所示)。一般来说,这种行为可以帮助我们:它提醒我们提供所需的所有值,并且如果使用了任何默认值,那么从代码中可以清楚地看到它们。

该怎么做

只需使用Yearjava.time。首先声明

public static final DateTimeFormatter TWO_YEAR_FORMATTER = new DateTimeFormatterBuilder()
        .appendValueReduced(ChronoField.YEAR, 2, 2, 1950)
        .toFormatter();

然后使用

    int year = Year.parse("99", TWO_YEAR_FORMATTER).getValue();
    System.out.println(year);

输出

  

1999

将我想要的基值插入1950年,以指定该年度99年(含)之内的年份。如果您想要包括今年的过去一年,您可以使用:

private static final Year base = Year.now(ZoneId.of("Asia/Kolkata")).minusYears(99);
public static final DateTimeFormatter TWO_YEAR_FORMATTER = new DateTimeFormatterBuilder()
        .appendValueReduced(ChronoField.YEAR, 2, 2, base.getValue())
        .toFormatter();
顺便说一句,不要相信我的话,但我认为Joda-Time使用当前年份减去30年作为基础或支点。如果是这样的话,在最后一个片段中使用30代替99将是最兼容的(所以也会给你你期望的1999年。)

答案 3 :(得分:1)

您需要提供DAY_OF_MONTHMONTH_OF_YEAR

的默认值
DateTimeFormatter TWO_YEAR_FORMATTER = new DateTimeFormatterBuilder()
                .appendPattern("yy")
                .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
                .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                .toFormatter();

此外,

  

Java-8默认使用2000-2099范围,而不像SimpleDateFormat   相对于今天而言,范围为-80年至+ 20年。

Full answer

由于你只解析了几年,为了将'99'作为'1999',你的代码应该是这样的:

DateTimeFormatter TWO_YEAR_FORMATTER = new DateTimeFormatterBuilder()
                .appendPattern("")
                .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
                .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                .appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2, LocalDate.now().minusYears(80))
                .toFormatter();

答案 4 :(得分:1)

您可以使用formatter.parse(input, Year::from)直接解析年份:

import java.time.*;
import java.time.format.*;
class Main {
  public static void main(String[] args) {
    DateTimeFormatter TWO_YEAR_FORMATTER = DateTimeFormatter.ofPattern("yy");
    Year year = TWO_YEAR_FORMATTER.parse("99", Year::from);
    System.out.println(year);
  }
}

请注意,这将输出2099。要输出1999,您应该使用特定的格式化程序,如the one suggested by Ole V.V. in their answer