(Извините за редактирование, я хотел, чтобы это было немного более читабельным, но не мог сделать это правильно, когда я первоначально написал ответ ... теперь это длина эссе, но вы идете ...)
Просто, чтобы добавить к тому, что уже было сказано, проблема возникает из-за того, что возвращенные Calendar
экземпляры готовятся по-другому.Лично я чувствую, что это недостаток дизайна, но для этого может быть веская причина.
Когда вы вызываете Calendar.getInstance()
, он создает новый GregorianCalendar
с использованием конструктора по умолчанию.Этот конструктор вызывает setCurrentTimeMillis(time)
с текущим системным временем, а затем вызывает защищенный метод complete()
.
Однако, когда вы создаете новый GregorianCalendar
с использованием созданного вами конструктора, complete()
никогда не будетназывается;вместо этого, среди прочего, только set(field, value)
вызывается для различных предоставляемых битов информации.Это все хорошо, но имеет некоторые запутанные последствия.
Когда в первом случае вызывается complete()
, проверяются переменные-члены, на которые ссылается пылесос, чтобы определить, какую информацию следует пересчитать.В результате получается ветвь, которая заставляет вычислять все поля (DAY
, WEEK_OF_MONTH
и т. Д.).Обратите внимание, что Calendar
действительно ленив;просто случается так, что использование этого метода создания экземпляров приводит к явному пересчету (или, в данном случае, первоначальному вычислению) на месте.
Итак, какое влияние это оказывает?Учитывая, что в случае создания второго объекта не было начального вычисления поля, два объекта имеют совершенно разные состояния.Первый содержит всю информацию о своих полях, а второй содержит только ту информацию, которую вы предоставили.Когда вы вызываете различные методы get*()
, это не должно иметь значения, потому что любые изменения должны провоцировать ленивый пересчет при извлечении информации.Однако порядок, в котором происходит этот пересчет, показывает различия между двумя различными начальными состояниями.
В вашем конкретном случае это связано со следующим соответствующим кодом в computeTime()
, который обязательно вызывается для вычисленияправильное время, когда вы запрашиваете его с помощью getTime()
:
boolean weekMonthSet = isSet[WEEK_OF_MONTH] || isSet[DAY_OF_WEEK_IN_MONTH];
...
boolean useDate = isSet[DATE];
if (useDate && (lastDateFieldSet == DAY_OF_WEEK
|| lastDateFieldSet == WEEK_OF_MONTH
|| lastDateFieldSet == DAY_OF_WEEK_IN_MONTH)) {
useDate = !(isSet[DAY_OF_WEEK] && weekMonthSet);
}
В первом случае все поля устанавливаются в соответствии с этим начальным вычислением.Это позволяет weekMonthSet
быть истинным, что, наряду с DAY_OF_WEEK
, которое вы указали при вызове для set(field, value)
, приводит к тому, что useDate
будет ложным.
Однако во втором случае, поскольку никакие поля не были рассчитаны, единственные установленные поля - это те, которые вы указали в конструкторе и при последующем вызове set(field, value)
.Таким образом, useDate
останется истинным, потому что isSet[DATE]
является истинным для вашего конструктора, но weekMonthSet
является ложным, поскольку другие поля в объекте нигде не были вычислены и не установлены вами.
КогдаuseDate
- истина, поскольку подразумевается, что она использует информацию о вашей дате, чтобы сгенерировать значение для времени.Когда useDate
ложно, он может использовать вашу DAY_OF_WEEK
информацию для вычисления ожидаемого времени, что приводит к разнице, которую вы видите.
Наконец, возникает вопрос о том, зачем звонить getTimeInMillis()
перед вызовомgetTime()
исправит неожиданное поведение.Как оказалось, поля будут пересчитаны в результате вашего вызова set(field, value)
в обоих объектах.Просто так происходит после времени, по какой-то (вероятно, подлинной) причине.Следовательно, принудительное вычисление времени один раз за секунду Calendar
по существу выровняет состояния двух объектов.После этого я считаю, что вызовы get*()
должны все работать согласованно для обоих объектов.
В идеале конструктор, который вы использовали во втором случае, должен выполнить этот начальный шаг вычисления во имя согласованности (хотя, возможно, дляиз соображений производительности это не было бы предпочтительным), но это не так, и это то, что вы получаете.
Итак, вкратце, как уже упоминалось, JodaTime ваш други, очевидно, эти классы менее.:)