需要查询Calendar实例以使日历设置生效

问题描述 投票:0回答:1

我有一个日历实例,从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 */的用途。

android calendar java.util.calendar
1个回答
1
投票

java.time和ThreeTenABP

    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

这是给你一年的最后一个星期二。没有必要进一步。

问题:我可以在Android上使用java.time吗?

是的,java.time适用于较旧和较新的Android设备。它至少需要Java 6。

  • 在Java 8及更高版本和更新的Android设备上(来自API级别26),现代API内置。
  • 在Java 6和7中获取ThreeTen Backport,现代类的后端(JST 310的ThreeTen;请参见底部的链接)。
  • 在(较旧的)Android上使用Android版的ThreeTen Backport。它被称为ThreeTenABP。并确保从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。

链接

© www.soinside.com 2019 - 2024. All rights reserved.