gpt4 book ai didi

java - Java 和 Android 中 Calendar 类的不同行为

转载 作者:IT老高 更新时间:2023-10-28 20:54:19 24 4
gpt4 key购买 nike

我正在检索一年中第一周的日期,我发现了非常奇怪的行为。

我在 Java 控制台应用程序和 Android 模拟器中测试了以下代码 fragment ,它产生了不同的输出。

    Calendar cal = Calendar.getInstance();
cal.set(Calendar.WEEK_OF_YEAR, 1);
cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(sdf.format(cal.getTime()));

产生了以下输出

Android 日志猫:2012/09/17(不正确)

Java 控制台:2012/01/01(正确)

奇怪的是,如果我在 Android 和 Java 中都使用以下代码,它会产生相同的正确输出。唯一的区别是我把上面代码的第 2 行和第 3 行交换了。

    Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
cal.set(Calendar.WEEK_OF_YEAR, 1);
System.out.println(sdf.format(cal.getTime()));

Android 日志猫:2012/01/01(正确)

Java 控制台:2012/01/01(正确)

我很想知道这件事。

提前致谢。

最佳答案

Calendar 类内部似乎有两个数据容器。

长时间保护

protected int[] 字段

所以当您调用 cal.set(Calendar.WEEK_OF_YEAR, 1) 时,您更改的是 fields 中的值,而不是 time类。

在 Java API 中

protected abstract void computeFields()

Converts the current millisecond time value time to calendar field values in fields[]. This allows you to sync up the calendar field values with a new time that is set for the calendar. The time is not recomputed first; to recompute the time, then the fields, call the complete() method.

我认为在 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[time=1348010308802,areFieldsSet=true,lenient=true,zone=org.apache.harmony.luni.internal.util.ZoneInfo["null",mRawOffset=0,mUseDst=false],firstDayOfWeek=1,minimalDaysInFirstWeek=4,ERA==1,YEAR==2012,MONTH==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,HOUR==11,HOUR_OF_DAY=23,MINUTE==18,SECOND==28,MILLISECOND==802,ZONE_OFFSET==0,DST_OFFSET==0]

2012.09.18

java.util.GregorianCalendar[time=?,areFieldsSet=false,lenient=true,zone=org.apache.harmony.luni.internal.util.ZoneInfo["null",mRawOffset=0,mUseDst=false],firstDayOfWeek=1,minimalDaysInFirstWeek=4,ERA==1,YEAR==2012,MONTH==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,HOUR==11,HOUR_OF_DAY=23,MINUTE==18,SECOND==28,MILLISECOND==802,ZONE_OFFSET==0,DST_OFFSET==0]

2012.01.03

java.util.GregorianCalendar[time=?,areFieldsSet=false,lenient=true,zone=org.apache.harmony.luni.internal.util.ZoneInfo["null",mRawOffset=0,mUseDst=false],firstDayOfWeek=1,minimalDaysInFirstWeek=4,ERA==1,YEAR==2012,MONTH==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,HOUR==11,HOUR_OF_DAY=23,MINUTE==18,SECOND==28,MILLISECOND==802,ZONE_OFFSET==0,DST_OFFSET==0]

2012.09.16

正如我们在上面看到的,字段中的值发生了变化,但是内部时间被表示为 ?,说明 time 没有与 fields< 同步

您使用 getTime() 方法获得了未同步的 time 并将其打印出来。

我认为 Android 中的日历旨在延迟同步,直到真正需要它为止。

添加

我在 Java API 中发现了以下内容:

Calendar fields can be changed using three methods: set(), add(), and roll().

set(f, value) changes field f to value. In addition, it sets an internal member variable to indicate that field f has been changed. Although field f is changed immediately, the calendar's milliseconds is not recomputed until the next call to get(), getTime(), or getTimeInMillis() is made. Thus, multiple calls to set() do not trigger multiple, unnecessary computations. As a result of changing a field using set(), other fields may also change, depending on the field, the field value, and the calendar system. In addition, get(f) will not necessarily return value after the fields have been recomputed. The specifics are determined by the concrete calendar class.

添加

为了检查“具体由具体的日历类决定”是否属实,我查看了Dalvik和JDK 6的实际代码。

Dalvik 日历中的设置方法

来自 https://www.codeaurora.org/git/projects/qrd-gb-dsds-7225/repository/revisions/cc99b832a941dc8cbb86f1607d04eb87935ddbfd/entry/android/dalvik/libcore/luni/src/main/java/java/util/Calendar.java

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();
}
}

具体的实现是完全不同的。要找出问题的确切原因,您应该详细查看这两种实现。

关于java - Java 和 Android 中 Calendar 类的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12481505/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com