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

时间:2019-02-24 14:55:20

标签: android calendar java.util.calendar

我有一个Calendar实例,它从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 */的目的。

1 个答案:

答案 0 :(得分: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反向端口,这是现代类的反向端口(JSR 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。

链接