Как преобразовать двузначный год в полный год, используя Java 8 time API - PullRequest
0 голосов
/ 06 июня 2018

Я хочу удалить библиотеку 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

Это вывод, который я ожидаю и который имеет смысл в моей ситуации.Однако, когда я пытаюсь выполнить ту же процедуру с API java.time, он создает исключение DatetimeParseException.Ниже приведен следующий код API java.time:

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

Stacktrace:

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

Я не смог увидеть причину стека трассировки.Было бы неплохо, если бы кто-нибудь помог мне разобраться в следующем сценарии, а также объяснить, как преобразовать двузначный год в полный год с помощью API времени Java 8.

Ответы [ 5 ]

0 голосов
/ 06 июня 2018

Вы можете проанализировать год напрямую, используя 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 года вы должны использовать специальный форматер, такой как , предложенный Оле В.В. в ответе .

0 голосов
/ 06 июня 2018

Почему это не сработало

java.time не предоставляет значения по умолчанию для месяца и дня месяца, как это делает Joda-Time.В сообщении говорится, что он не может получить LocalDate только за год или, наоборот, ему не хватает месяца и дня (вы можете указать собственные значения по умолчанию, как показано в ответ Михаила Холодкова ).Как правило, это поведение помогает нам: оно напоминает нам о необходимости ввода всех необходимых значений и дает понять из кода, используются ли какие-либо значения по умолчанию и какие.

Что делать вместо

Просто используйте 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 год).

0 голосов
/ 06 июня 2018

Проблема в том, что вы не можете разобрать год самостоятельно в 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).

0 голосов
/ 06 июня 2018

Необходимо указать значения по умолчанию для 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();
0 голосов
/ 06 июня 2018

Вы не можете создать LocalDate, потому что String, который вы даете, не предоставляет информацию, необходимую для заполнения всех обязательных полей.

Вы можете создать Year, хотя

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