如何使用 Java 8 次 API 将两位数年份转换为完整年份
How to convert two digit year to full year using Java 8 time API
我希望从我的项目中删除 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.
将两位数年份转换为全年,那就太好了
您无法创建 LocalDate
,因为您提供的 String
没有提供填写所有必填字段所需的信息。
虽然
您可以创建Year
Year parsed = Year.parse("99", TWO_YEAR_FORMATTER);
int year = parsed.getValue();
问题是您无法将年份单独解析为 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)。
您需要为 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 uses the range 2000-2099 per default, not like SimpleDateFormat
the range -80 years until +20 years relative to today.
由于您只解析年份,为了将“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();
为什么它不起作用
java.time
不像 Joda-Time 那样提供月份和日期的默认值。该消息表示它无法仅从一年中获取 LocalDate
,或者相反,它缺少月份和日期(不过,您可以提供自己的默认值,如 中所示)。通常这种行为是为了帮助我们:它提醒我们提供所有需要的值,并从代码中清楚地说明是否使用了任何默认值,以及使用了哪些默认值。
该怎么做
只需使用 java.time
的 Year
class。先声明
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)。
您可以直接使用 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,您应该使用特定的格式化程序,例如 .
我希望从我的项目中删除 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.
将两位数年份转换为全年,那就太好了您无法创建 LocalDate
,因为您提供的 String
没有提供填写所有必填字段所需的信息。
虽然
您可以创建Year
Year parsed = Year.parse("99", TWO_YEAR_FORMATTER);
int year = parsed.getValue();
问题是您无法将年份单独解析为 LocalDate。 LocalDate 需要比这更多的信息。
您可以使用格式化程序的 parse
方法,它会给您一个 TemporalAccessor
,然后从中获取年份字段:
int year = TWO_YEAR_FORMATTER.parse("99").get(ChronoField.YEAR);
System.out.println(year);
解决两者之间的差异:这是两个不同的 API。是的,它们非常相似,并且 java.time
包是由 JodaTime 的设计决策所决定的,但它从未打算成为它的直接替代品。
如果您想更改基准年,请参阅
您需要为 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 uses the range 2000-2099 per default, not like SimpleDateFormat the range -80 years until +20 years relative to today.
由于您只解析年份,为了将“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();
为什么它不起作用
java.time
不像 Joda-Time 那样提供月份和日期的默认值。该消息表示它无法仅从一年中获取 LocalDate
,或者相反,它缺少月份和日期(不过,您可以提供自己的默认值,如
该怎么做
只需使用 java.time
的 Year
class。先声明
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)。
您可以直接使用 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,您应该使用特定的格式化程序,例如