某些 Android 设备上的日历 returns 一周的糟糕开始

Calendar returns bad start of week on some Android devices

我想获取本周第一天的日期。所以我是这样实现的:

fun getFirstDayInCurrentWeek(): Date {
    val calendar = Calendar.getInstance()
    calendar.clear(MILLISECOND)
    calendar.clear(SECOND)
    calendar.clear(MINUTE)
    calendar.set(HOUR_OF_DAY, 0)
    calendar.set(DAY_OF_WEEK, 1)
    return calendar.time
}

它适用于大多数设备,但有时 returns 下周的第一天。我不明白为什么。

类来自java.util.*

编辑: 今天 (28.05.2018) 只需记录此函数的结果,您将看到 27.05.2018 或 03.06.2018。这些设备具有相同的语言环境和相同的时区。

一周的第一天因国家/地区而异。如果您希望它对所有用户都相同,您可以将 Locale 传递给 Calendar

Calendar currentCalendar = Calendar.getInstance(new Locale("en","UK"));

同样来自this的回答,你可以使用方法setFirstDayOfWeek()来设置一周的第一天。该方法只能影响 WEEK_OF_MONTH 或 WEEK_OF_YEAR 的 return 值。对于 DAY_OF_WEEK,它什么都不做。

你可以实现类似的东西:

Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
int rec = cal.get(Calendar.WEEK_OF_MONTH);
System.out.println(rec);

阅读更多关于 API HERE

如果我没理解错的话,你想把星期天当作一周的第一天(就像在美国一样)。

    WeekFields wf = WeekFields.SUNDAY_START;
    LocalDate today = LocalDate.now(ZoneId.of("Europe/Warsaw"));
    LocalDate firstDayOfThisWeek = today.with(wf.dayOfWeek(), 1);
    System.out.println(firstDayOfThisWeek);

我正在写 Java 代码,相信你可以转换到 Kotlin。 运行今天(5 月 29 日,星期二)打印了

2018-05-27

如果您希望星期一作为一周的第一天(如波兰和国际标准所说),只需使用 WeekFields.ISO 而不是 WeekFields.SUNDAY_START。如果您希望它依赖于区域设置,请使用例如 WeekFields.of(Locale.forLanguageTag("pl-PL")).

另一个可能更清晰的选项是:

    LocalDate firstDayOfThisWeek = today
            .with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));

在这两种情况下,我都使用 java.time,现代 Java 日期和时间 API。我认为这是一个很好的例子,说明它提供了更清晰的代码,与旧的日期和时间 class 相比,情况通常如此 Calendar.

你的代码出了什么问题?

据我了解文档,您的代码应该给出当前周的星期日。 Calendar 使用 1 表示星期日。您可能已使用 calendar.set(DAY_OF_WEEK, SUNDAY) 获得完全相同的结果。当我今天 运行 它时,如果使用星期日作为一周的第一天,我得到 5 月 27 日,如果使用星期一作为第一天,我得到 6 月 3 日(这意味着星期日是一周的最后一天)。但是,文档不是很清楚,Calendar class 可能会造成混淆。无论如何,这可能也是您在不同设备上尝试时发生的情况:它们对周有不同的定义。如果您可以单独配置星期定义,即使它们具有相同的语言环境,这也是可能的。

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

是的,java.time 在新旧 Android 设备上都能很好地工作。它只需要至少 Java 6.

  • 在 Java 8 和更高版本以及较新的 Android 设备上(据我所知,来自 API 级别 26)现代 API 是内置的。
  • 在 Java 6 和 7 中获取 ThreeTen Backport,新 classes 的 backport(ThreeTen 用于 JSR 310;请参阅底部的链接)。
  • 在(较旧的)Android 使用 ThreeTen Backport 的 Android 版本。它叫做 ThreeTenABP。并确保使用子包从 org.threeten.bp 导入日期和时间 classes。

链接