我有一个日历实例,从12月的第一天开始。我试图将该Calendar实例设置为一年的最后一个星期二。在设置一年的最后一天和星期几之间,Calendar实例将恢复为原始时间:
Calendar cal = ....;
Log.d(TAG, String.format("Starting here %d-%d-%d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH)));
cal.set(Calendar.DAY_OF_YEAR, cal.getActualMaximum(Calendar.DAY_OF_YEAR));
cal.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);
Log.d(TAG, String.format("Ending here %d-%d-%d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH)));
/* Other stuff */
给我2017年和2018年的产量:
2017:
Starting here 2017-12-1
Ending here 2017-11-28
2018:
Starting here 2018-12-1
Ending here 2018-11-27
但是,如果我从Calendar实例中检索数据,它可以正常工作:
Calendar cal = ....;
Log.d(TAG, String.format("Starting here %d-%d-%d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH)));
cal.set(Calendar.DAY_OF_YEAR, cal.getActualMaximum(Calendar.DAY_OF_YEAR));
// Ask the Calendar instance for information
long dummyValue = cal.getTimeInMillis();
cal.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);
Log.d(TAG, String.format("Ending here %d-%d-%d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH)));
/* Other stuff */
给我2017年和2018年的产量:
2017:
Starting here 2017-12-1
Ending here 2018-1-2
2018:
Starting here 2018-12-1
Ending here 2019-1-1
是的,我知道第二组值的日期不是最后一个星期二。这就是/* Other stuff */
的用途。
LocalDate myLocalDate = LocalDate.of(2017, Month.DECEMBER, 1);
System.out.format("Starting here: %s%n", myLocalDate);
LocalDate lastTuesdayOfYear = myLocalDate
.with(TemporalAdjusters.lastDayOfYear())
.with(TemporalAdjusters.previousOrSame(DayOfWeek.TUESDAY));
System.out.format("Ending here: %s%n", lastTuesdayOfYear);
2017年产出:
Starting here: 2017-12-01 Ending here: 2017-12-26
2018年:
Starting here: 2018-12-01 Ending here: 2018-12-25
这是给你一年的最后一个星期二。没有必要进一步。
是的,java.time适用于较旧和较新的Android设备。它至少需要Java 6。
org.threeten.bp
导入子包的日期和时间类。Calendar
课程令人困惑。在您的情况下,它的行为符合文档。请允许我引述:
日历字段分辨率
当从日历字段计算日期和时间时,......可能存在不一致的信息(例如1996年7月15日星期二(格里高利) - 1996年7月15日实际上是星期一)。
Calendar
将以下列方式解析日历字段值以确定日期和时间。如果日历字段值中存在任何冲突,
Calendar
会为最近设置的日历字段提供优先级。以下是日历字段的默认组合。将使用由最近设置的单个字段确定的最新组合。对于日期字段:
YEAR + MONTH + DAY_OF_MONTH YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK YEAR + DAY_OF_YEAR YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
…
在你的情况下DAY_OF_WEEK
最近设置。 DAY_OF_WEEK
是上述五种组合中的三种。它选择了哪一个我不知道。它们都不包括DAY_OF_YEAR
,你设置的另一个领域,所以没有使用DAY_OF_YEAR
。这解释了你看到的行为。如果你坚持使用Calendar
,你应该能够到达cal.set(Calendar.DAY_OF_WEEK_IN_MONTH, -1);
的某个地方,因为负数值从月末倒数。
然而,Calendar
不仅设计糟糕而且容易混淆,而且也很久了。所以考虑使用java.time。
java.time
首次被描述。java.time
的后端到Java 6和7(JST-310的ThreeTen)。