Android 7.x (API24) WEEK_OF_MONTH 日历错误?

标签 android calendar android-7.0-nougat android-7.1-nougat

我们在使用 Calendar 的 Android 7 (API 24/25) 中遇到了一些奇怪的行为。

给定这段相当简单的代码:

SimpleDateFormat month_date = new SimpleDateFormat("dd.MM.YYYY");
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY);
cal.setFirstDayOfWeek(Calendar.MONDAY);

for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) {
    Calendar start = ((Calendar) cal.clone());
    start.set(2017, month, 1);

    Calendar end = ((Calendar) start.clone());
    end.set(Calendar.DAY_OF_MONTH, end.getActualMaximum(Calendar.DAY_OF_MONTH));

    Log.d("CAL", "\n    Date Start: " + month_date.format(start.getTime()) + " " +
        " WEEK_OF_MONTH: " + start.get(Calendar.WEEK_OF_MONTH)
    );
    Log.d("CAL", "\n    Date End: " + month_date.format(end.getTime()) +
        " WEEK_OF_MONTH: " + end.get(Calendar.WEEK_OF_MONTH)
       );
}

在 Android 4.0x、5.x 和 6.x 上运行显示 WEEK_OF_MONTH 的正确值:

 Date Start: 01.01.2016  WEEK_OF_MONTH: 1
 Date End: 31.01.2017 WEEK_OF_MONTH: 6
 Date Start: 01.02.2017  WEEK_OF_MONTH: 1
 Date End: 28.02.2017 WEEK_OF_MONTH: 5
 Date Start: 01.03.2017  WEEK_OF_MONTH: 1
 Date End: 31.03.2017 WEEK_OF_MONTH: 5
 Date Start: 01.04.2017  WEEK_OF_MONTH: 1
 Date End: 30.04.2017 WEEK_OF_MONTH: 5
 Date Start: 01.05.2017  WEEK_OF_MONTH: 1
 Date End: 31.05.2017 WEEK_OF_MONTH: 5
 Date Start: 01.06.2017  WEEK_OF_MONTH: 1
 Date End: 30.06.2017 WEEK_OF_MONTH: 5
 Date Start: 01.07.2017  WEEK_OF_MONTH: 1
 Date End: 31.07.2017 WEEK_OF_MONTH: 6
 Date Start: 01.08.2017  WEEK_OF_MONTH: 1
 Date End: 31.08.2017 WEEK_OF_MONTH: 5
 Date Start: 01.09.2017  WEEK_OF_MONTH: 1
 Date End: 30.09.2017 WEEK_OF_MONTH: 5
 Date Start: 01.10.2017  WEEK_OF_MONTH: 1
 Date End: 31.10.2017 WEEK_OF_MONTH: 6
 Date Start: 01.11.2017  WEEK_OF_MONTH: 1
 Date End: 30.11.2017 WEEK_OF_MONTH: 5
 Date Start: 01.12.2017  WEEK_OF_MONTH: 1
 Date End: 31.12.2017 WEEK_OF_MONTH: 5

在 Android 7.x 上运行损坏 WEEK_OF_MONTH:

 Date Start: 01.01.2016  WEEK_OF_MONTH: 0
 Date End: 31.01.2017 WEEK_OF_MONTH: 5
 Date Start: 01.02.2017  WEEK_OF_MONTH: 1
 Date End: 28.02.2017 WEEK_OF_MONTH: 5
 Date Start: 01.03.2017  WEEK_OF_MONTH: 1
 Date End: 31.03.2017 WEEK_OF_MONTH: 5
 Date Start: 01.04.2017  WEEK_OF_MONTH: 0
 Date End: 30.04.2017 WEEK_OF_MONTH: 4
 Date Start: 01.05.2017  WEEK_OF_MONTH: 1
 Date End: 31.05.2017 WEEK_OF_MONTH: 5
 Date Start: 01.06.2017  WEEK_OF_MONTH: 1
 Date End: 30.06.2017 WEEK_OF_MONTH: 5
 Date Start: 01.07.2017  WEEK_OF_MONTH: 0
 Date End: 31.07.2017 WEEK_OF_MONTH: 5
 Date Start: 01.08.2017  WEEK_OF_MONTH: 1
 Date End: 31.08.2017 WEEK_OF_MONTH: 5
 Date Start: 01.09.2017  WEEK_OF_MONTH: 0
 Date End: 30.09.2017 WEEK_OF_MONTH: 4
 Date Start: 01.10.2017  WEEK_OF_MONTH: 0
 Date End: 31.10.2017 WEEK_OF_MONTH: 5
 Date Start: 01.11.2017  WEEK_OF_MONTH: 1
 Date End: 30.11.2017 WEEK_OF_MONTH: 5
 Date Start: 01.12.2017  WEEK_OF_MONTH: 0
 Date End: 31.12.2017 WEEK_OF_MONTH: 4

我们在 API 24 中找不到任何关于 Calendar 的记录更改。

知道如何解决这个问题吗?

我们已经为 WEEK_OF_MONTH 实现了我们自己的方法,返回与 Android 6.x 相同的值,但从它的外观来看,set(WEEK_OF_MONTH) 也被破坏了。 使用 Joda 重写代码不是一种选择。

最佳答案

您可以使用setMinimalDaysInFirstWeek() 方法来change how the weeks are counted :

Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY);
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(1);

这将为每月的第几周生成正确的值。


您说过用 Joda-Time 重写代码不是一种选择,但是另一个 API 呢?

在 Android 中,您可以使用 ThreeTen Backport ,Java 8 的新日期/时间类的一个很好的反向移植,以及 ThreeTenABP (更多关于如何使用它的信息 here)。

顺便说一句,Joda-Time 处于维护模式并且正在被新的 API 取代,所以我不建议用它开始一个新项目。即使在 joda's website它说:“请注意,Joda-Time 被认为是一个基本“完成”的项目。没有计划进行重大增强。如果使用 Java SE 8,请迁移到 java.time (JSR-310)。”.

下面的类在 org.threeten.bp 包下。代码将是这样的:

import java.util.Locale;
import org.threeten.bp.DayOfWeek;
import org.threeten.bp.LocalDate;
import org.threeten.bp.Month;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.DateTimeFormatterBuilder;
import org.threeten.bp.temporal.TemporalAdjusters;
import org.threeten.bp.temporal.WeekFields;

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // day and month
    .appendPattern("dd.MM.")
    // week based year (equivalent to YYYY in SimpleDateFormat)
    .appendValue(WeekFields.ISO.weekBasedYear())
    // create formatter
    .toFormatter(Locale.GERMANY);

// week starting at monday, consider week=1 even if it has 1 day (default is 4)
WeekFields wf = WeekFields.of(DayOfWeek.MONDAY, 1);
for (Month month : Month.values()) {
    LocalDate start = LocalDate.of(2017, month, 1);
    LocalDate end = start.with(TemporalAdjusters.lastDayOfMonth());

    System.out.println("Date Start: " + fmt.format(start) + " " + " WEEK_OF_MONTH: " + start.get(wf.weekOfMonth()));
    System.out.println("Date End: " + fmt.format(end) + " WEEK_OF_MONTH: " + end.get(wf.weekOfMonth()));
}

输出将是:

Date Start: 01.01.2016  WEEK_OF_MONTH: 1
Date End: 31.01.2017 WEEK_OF_MONTH: 6
Date Start: 01.02.2017  WEEK_OF_MONTH: 1
Date End: 28.02.2017 WEEK_OF_MONTH: 5
Date Start: 01.03.2017  WEEK_OF_MONTH: 1
Date End: 31.03.2017 WEEK_OF_MONTH: 5
Date Start: 01.04.2017  WEEK_OF_MONTH: 1
Date End: 30.04.2017 WEEK_OF_MONTH: 5
Date Start: 01.05.2017  WEEK_OF_MONTH: 1
Date End: 31.05.2017 WEEK_OF_MONTH: 5
Date Start: 01.06.2017  WEEK_OF_MONTH: 1
Date End: 30.06.2017 WEEK_OF_MONTH: 5
Date Start: 01.07.2017  WEEK_OF_MONTH: 1
Date End: 31.07.2017 WEEK_OF_MONTH: 6
Date Start: 01.08.2017  WEEK_OF_MONTH: 1
Date End: 31.08.2017 WEEK_OF_MONTH: 5
Date Start: 01.09.2017  WEEK_OF_MONTH: 1
Date End: 30.09.2017 WEEK_OF_MONTH: 5
Date Start: 01.10.2017  WEEK_OF_MONTH: 1
Date End: 31.10.2017 WEEK_OF_MONTH: 6
Date Start: 01.11.2017  WEEK_OF_MONTH: 1
Date End: 30.11.2017 WEEK_OF_MONTH: 5
Date Start: 01.12.2017  WEEK_OF_MONTH: 1
Date End: 31.12.2017 WEEK_OF_MONTH: 5

关于Android 7.x (API24) WEEK_OF_MONTH 日历错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44849694/

相关文章:

javascript - Bootstrap 日历不显示

ios - Xcode : Event not created in Calendar : issue With Timezone?

android - Nougat 上的 Html.fromHtml 不会调用自定义 HtmlHandler

android - 为什么 Android N 在使用 Bundles 时会抛出 TransactionTooLargeException?

java - 如何向 fragment 发出异步任务尚未完成其任务的信号

android - 如何在android中获取存储目录的路径

android - Xamarin Forms 图像不显示

Android:点击保存后相机崩溃

java - 为什么 Calendar.getActualMaximum 不起作用

android - 作用域目录访问 API 抛出 NullPointerException