Почему метод add () в GregorianCalendar не работает?

Я создал класс, который представляет возможного пользователя библиотечной системы. В момент создания этого экземпляра мне нужно установить два поля: signingUpDate и expirationDate, оба являются григорианским календарем.

signingUpDate - это дата в момент создания, а expirationDate - это signingUpDate + 5 лет.

public class User {

    private GregorianCalendar signingUpDate;
    private GregorianCalendar expirationDate;

    public User(){
        setSigningUpDate;
        setExpirationDate;
    }

    private void setExpirationDate() {
        this.expirationDate = new GregorianCalendar();
        expirationDate.add(GregorianCalendar.YEAR, 5);
    }

    private void setSigningUpDate() {
        this.signingUpDate=new GregorianCalendar();
    }

Когда я использую метод add(), expirationDate не меняется. Я попытался отладить и заметил, что поле areFieldsSet становится ложным. Но я не понимал значения этого поля. Кто-нибудь может мне помочь?

Похоже, что вы на самом деле не вызов ваши методы в вашем конструкторе. Я сомневаюсь, что это код, который вы действительно используете. Не могли бы вы опубликовать минимальный воспроизводимый пример?

khelwood 04.12.2018 14:29

Старый добрый, нет, старый плохой GregorianCalendar. Лучшее, что вы можете сделать, - это использовать LocalDate или другой класс из java.time, современный API даты и времени Java. Он вытеснил GregorianCalendar и другие старые классы даты и времени почти 5 лет назад.

Ole V.V. 04.12.2018 14:29

Что такое GregorianCalendar.years? Вы имели ввиду Calendar.YEAR? Во всяком случае, я согласен с @ OleV.V. что это очень старый. Если возможно, поменяйте на java.time

Robert Kock 04.12.2018 14:39

Мы бы помогли вам, если бы вы разместили код, который может компилироваться и запускаться и показывать нежелательное поведение. Это похоже на то, как будто мы тратим свою энергию, указывая на опечатки, не зная, имеют ли они какое-либо отношение к настоящей причине вашей проблемы (я предполагаю, что это не так).

Ole V.V. 04.12.2018 14:41

Спасибо за правку, это хорошо. Я все еще получаю setSigningUpDate cannot be resolved to a type из-за синтаксической ошибки в том, что должно было быть вызовом метода.

Ole V.V. 04.12.2018 14:51

Извините, я работал над этим ... Это был большой сценарий для публикации, и я переделал код, чтобы попробовать объяснения в ответах. В любом случае, спасибо.

Alessandro Bonadei 04.12.2018 14:58

К вашему сведению, ужасно неприятные старые классы даты и времени, такие как java.util.Date, java.util.Calendar и java.text.SimpleDateFormat, теперь являются наследие, вытесненными классами java.time, встроенными в Java 8 и новее. См. Руководство от Oracle.

Basil Bourque 04.12.2018 22:29
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
7
225
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ошибка (?) GregorianCalendar, вы можете вызвать getTime, чтобы «обновить» его после добавления 5 лет:

signingUpDate.add(Calendar.YEAR, 5);
signingUpDate.getTime();

Другое решение, используйте вместо него пакет java.time, например, java.time.LocalDate.

Он разработан и задокументирован (хотя документацию очень сложно читать и понимать). Так что если баг, то это ошибка в дизайне (и ИМХО не единственная), а не в коде.

Ole V.V. 04.12.2018 14:56

@ OleV.V. Ага. Поэтому я добавляю (?) за bug.

xingbin 04.12.2018 14:56

java.time

public class User {

    private static final ZoneId ZONE = ZoneId.of("America/Kentucky/Monticello");
    private static final Period VALIDITY = Period.ofYears(5);

    private LocalDate signingUpDate;
    private LocalDate expirationDate;

    public User() {
        setSigningUpDate();
        setExpirationDate();
    }

    private void setSigningUpDate() {
        this.signingUpDate = LocalDate.now(ZONE);
    }

    private void setExpirationDate() {
        this.expirationDate = signingUpDate.plus(VALIDITY);
    }

    @Override
    public String toString() {
        return "Signed up " + signingUpDate + " expires " + expirationDate; 
    }
}

java.time, современный API даты и времени Java, не содержит неприятных сюрпризов GregorianCalendar и других классов даты и времени из Java 1.0 и 1.1. Таким образом, хорошее решение - отказаться от старых классов и использовать вместо них современные.

Что пошло не так в вашем коде?

В вашем коде ничего плохого не было. Я также не совсем уверен, что вас смутило, но класс GregorianCalendar определенно сбивает с толку, так что я тоже не удивлен. Возможно, вы заглянули внутрь объекта GregorianCalendar в своем отладчике и увидели, что год не изменился, а значение areFieldsSet было изменено на false. Они пытались задокументировать это сбивающее с толку поведение, но, поскольку оно настолько неестественно и отличается от того, что вы ожидали, документацию также трудно читать и понимать.

Ссылка на сайт

Учебник Oracle: Дата и время объясняет, как использовать java.time.

Другие вопросы по теме