Ответ 1
Ты, конечно же, дал мне начальника, но я понял это.
Технические характеристики
Значения полей календаря можно задать, вызвав методы набора. Любые значения полей, заданные в Календаре, не будут интерпретироваться, пока не потребуется вычислять его значение времени (миллисекунды из эпохи) или значения полей календаря. Вызов get, getTimeInMillis, getTime, add и roll включает такие вычисления.
Это означает, что всякий раз, когда вы меняете свои значения с помощью set, вы должны сказать ему, чтобы обновить себя, используя один из методов get для распространения изменений. Однако ваш код не был, за исключением случаев, когда вы раскомментировали код. Так что что-то в вашем коде явно не играло хорошо с вашими наборами в computeTime.
Где делали плохое
Итак... мы можем посмотреть на эту устаревшую, но тем не менее чудовищно трудную для навигации копию GregorianCalendar источник и проанализируйте, что происходит, когда вы делаете getTime() после установки дня недели со всеми другими каналами.
Ух, копирование из этого - боль. Я пройду через это.
Сначала мы знаем, что getTimeInMillis()
вызывает computeTime()
в строке 505
.
Вы объявили экземпляр Календаря. Он имеет предопределенные значения. Сегодня, если быть точным. А также мы на третьей неделе сентября. Важно позже!
Теперь мы назначим ваш день в строке 511
. Здесь ваш день установлен на 22.
int day = fields[DAY_OF_MONTH];
Линия 523
- это то, где дела идут бонкерами и нарушают вашу дату! Мы оцениваем это как false
и переходим к else в строке 553
.
if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR]))
//evaluates to true
Мы вводим оператор if в 555
, потому что DAY_OF_WEEK
установлен. И у нас есть DAY_OF_WEEK_IN_MONTH
, но мы не поставили его сами. Календарь сделал, когда он был создан. Помните, что 3-я неделя сентября? Да, он здесь, где он нас укусил. Он рассчитывает воскресенье 3-й недели в июне и перезаписывает наш день = 22 к 15-му, что является третьим воскресеньем в июне.
if (isSet[DAY_OF_WEEK]) { //yup we set this
int first = getFirstDayOfMonth(year, month);
// 3: YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
if (isSet[DAY_OF_WEEK_IN_MONTH]) { //we didn't set this, but it been set!
if (fields[DAY_OF_WEEK_IN_MONTH] < 0) {
month++;
first = getFirstDayOfMonth(year, month);
day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH]);
} else
day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1);
// 15 = 1 + 7 * (3 - 1)
int offs = fields[DAY_OF_WEEK] - first;
if (offs < 0)
offs += 7;
day += offs;
}
}
Как решить проблему
Проверьте исходный javadoc на метод set
, который вы вызывали с помощью года, месяца и дня.
Устанавливает значения для полей календаря YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY и MINUTE. Предыдущие значения других полей сохраняются. Если это не требуется, сначала вызовите clear().
Конечно, добавив dc.clear();
, прежде чем ваш набор вернет желаемый результат. Я не прошел через него, но, учитывая странное поведение, которое в настоящее время испытано, лучшим вариантом будет getTime()
после каждого изменения, чтобы ваше время не стало неожиданным результатом.
Итак, в основном, проблема заключалась в том, что у вас были пол-грязные данные с полу-новыми данными, которые противоречили себе и перезаписывали вещи. Если бы этот код был запущен на следующей неделе, вы бы даже не поймали ошибку. Как это для неудобного зависящего от времени состояния?