11

我希望从我的项目中删除 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 将两位数年份转换为全年,那就太好了。

4

5 回答 5

11

问题是您不能单独将一年解析为 LocalDate。LocalDate 需要更多信息。

您可以使用parse格式化程序的方法,它会给您一个TemporalAccessor,然后从中获取年份字段:

int year = TWO_YEAR_FORMATTER.parse("99").get(ChronoField.YEAR);
System.out.println(year);

解决两者之间的差异:这是两个不同的 API。是的,它们非常相似,并且该java.time软件包是由 JodaTime 的设计决定提供的,但它从未打算成为它的直接替代品。

如果您想更改基准年份,请参阅此答案(默认情况下,“99”将解析为 2099 而不是 1999)。

于 2018-06-06T12:10:12.460 回答
5

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

你可以创建Year一个

Year parsed = Year.parse("99", TWO_YEAR_FORMATTER);
int year = parsed.getValue();
于 2018-06-06T12:06:14.747 回答
5

为什么它不起作用

java.time不像 Joda-Time 那样提供月份和月份的默认值。该消息说它不能LocalDate仅从一年中获取 a,或者相反,它缺少月份和日期(不过,您可以提供自己的默认值,如Mikhail Kholodkov 的回答所示)。一般来说,这种行为是为了帮助我们:它提醒我们提供所有需要的值,并从代码中清楚地说明是否使用了任何默认值,以及使用哪个。

该怎么做

只需使用Year. java.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)。

于 2018-06-06T12:29:59.203 回答
1

您需要为DAY_OF_MONTH和提供默认值MONTH_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 年。

完整答案

由于您仅解析年份,因此为了将 '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();
于 2018-06-06T12:18:55.963 回答
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,您应该使用特定的格式化程序,例如Ole VV 在他们的 answer 中建议的格式化程序。

于 2018-06-06T12:41:01.300 回答