Ответ 1
Кажется, что в классе Calendar есть два контейнера данных.
protected long time
protected int[] fields
Поэтому, когда вы вызываете cal.set(Calendar.WEEK_OF_YEAR, 1)
, вы изменяете значения в fields
, а не time
этого класса.
В API Java
protected abstract void computeFields()
Преобразует текущее значение времени миллисекундного времени в значения полей календаря в полях []. Это позволяет синхронизировать значения поля календаря с новым временем, установленным для календаря. Время не пересчитывается сначала; чтобы перекомпилировать время, затем поля, вызовите метод complete().
Я думаю, что в первом случае Android computeFields()
не называется внутренне.
Чтобы проверить мою теорию, я проверил следующий код:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
Calendar cal = Calendar.getInstance();
System.out.println(cal);
System.out.println(sdf.format(cal.getTime()));
cal.set(Calendar.WEEK_OF_YEAR, 1);
System.out.println(cal);
System.out.println(sdf.format(cal.getTime()));
cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(cal);
System.out.println(sdf.format(cal.getTime()));
LogCat:
java.util.GregorianCalendar [ время = 1348010308802, areFieldsSet = истина, мягок = верно, зона = org.apache.harmony.luni.internal.util.ZoneInfo [ "нулевой" , mRawOffset = 0, mUseDst = ложь], firstDayOfWeek = 1, minimalDaysInFirstWeek = 4, ERA == 1, == Год 2012, Месяц == 8, WEEK_OF_YEAR == 38, WEEK_OF_MONTH == 4, DAY_OF_MONTH == 18, day_of_year == 262, DAY_OF_WEEK == 3, DAY_OF_WEEK_IN_MONTH == 3, AM_PM == 1, ЧАС == 11, HOUR_OF_DAY = 23, МИНУТНЫЙ == 18, ВТОРОЙ == 28, миллисекунды = = 802, ZONE_OFFSET == 0, DST_OFFSET == 0]
2012.09.18
java.util.GregorianCalendar [ время =?, areFieldsSet = ложь, мягок = верно, зона = org.apache.harmony.luni.internal.util.ZoneInfo [ "нулевой" , mRawOffset = 0, mUseDst = ложь], firstDayOfWeek = 1, minimalDaysInFirstWeek = 4, ERA == 1, == Год 2012, Месяц == 8, WEEK_OF_YEAR == 1, WEEK_OF_MONTH == 4, DAY_OF_MONTH == 18, day_of_year == 262, DAY_OF_WEEK == 3, DAY_OF_WEEK_IN_MONTH == 3, AM_PM == 1, ЧАС == 11, HOUR_OF_DAY = 23, МИНУТНЫЙ == 18, ВТОРОЙ == 28, миллисекунды = = 802, ZONE_OFFSET == 0, DST_OFFSET == 0]
2012.01.03
java.util.GregorianCalendar [ время =?, areFieldsSet = ложь, мягок = верно, зона = org.apache.harmony.luni.internal.util.ZoneInfo [ "нулевой" , mRawOffset = 0, mUseDst = ложь], firstDayOfWeek = 1, minimalDaysInFirstWeek = 4, ERA == 1, == Год 2012, Месяц == 8, WEEK_OF_YEAR == 1, WEEK_OF_MONTH == 4, DAY_OF_MONTH == 18, day_of_year == 262, DAY_OF_WEEK == 1, DAY_OF_WEEK_IN_MONTH == 3, AM_PM == 1, ЧАС == 11, HOUR_OF_DAY = 23, МИНУТНЫЙ == 18, ВТОРОЙ == 28, миллисекунды = = 802, ZONE_OFFSET == 0, DST_OFFSET == 0]
2012.09.16
Как мы видим выше, значения в полях изменяются, но внутреннее время обозначается как ?
, говоря, что time
не синхронизируется с fields
.
Вы получили несинхронизированный time
с помощью метода getTime()
и распечатали его.
Я думаю, что Календарь в Android предназначен для задержки синхронизации, пока это действительно не понадобится.
ADDED
Я нашел следующее в Java API:
Календарные поля можно изменить тремя способами: set(), add() и roll().
set (f, value) изменяет поле f на значение. Кроме того, он устанавливает внутреннюю переменную-член, чтобы указать, что поле f было изменено. Хотя поле f немедленно изменяется, календарные миллисекунды не пересчитываются до тех пор, пока следующий вызов get(), getTime() или getTimeInMillis() не будет сделан. Таким образом, множественные вызовы set() не запускают несколько ненужных вычислений. В результате изменения поля с помощью set() другие поля также могут изменяться в зависимости от поля, значения поля и системы календаря. Кроме того, get (f) не обязательно будет возвращать значение после перераспределения полей. Специфика определяется конкретным классом календаря.
ADDED
Чтобы проверить, является ли спецификацией конкретного класса календаря, я проверил действительные коды Dalvik и JDK 6.
Установить метод в календаре Dalvik
public void set(int field, int value) {
fields[field] = value;
isSet[field] = true;
areFieldsSet = isTimeSet = false;
if (field > MONTH && field < AM_PM) {
lastDateFieldSet = field;
}
if (field == HOUR || field == HOUR_OF_DAY) {
lastTimeFieldSet = field;
}
if (field == AM_PM) {
lastTimeFieldSet = HOUR;
}
}
Установить метод в календаре JDK 6
public void set(int field, int value) {
if (isLenient() && areFieldsSet && !areAllFieldsSet) {
computeFields();
}
internalSet(field, value);
isTimeSet = false;
areFieldsSet = false;
isSet[field] = true;
stamp[field] = nextStamp++;
if (nextStamp == Integer.MAX_VALUE) {
adjustStamp();
}
}
Конкретные реализации довольно разные. Чтобы выяснить точную причину вашей проблемы, вы должны подробно рассмотреть обе реализации.