【问题标题】:Calendar returns wrong week日历返回错误的星期
【发布时间】:2018-11-26 14:47:12
【问题描述】:

所以我需要获取本周星期一的毫秒时间和本周星期日的毫秒时间,并且下面的代码可以正常工作,直到我在模拟器上安装应用程序,如果我将时间设置为星期日,它会返回 Jun 18 - Jun 24 ,但在三星 Galaxy s5 上返回 Jun 11 - Jun 17 <- this is how it should show 我做错了吗?

getMondayTime 方法返回星期一的毫秒数

private fun getMondayTime(): Long{
    val calendar = Calendar.getInstance()
    calendar.timeInMillis = System.currentTimeMillis()
    calendar.firstDayOfWeek = Calendar.MONDAY
    calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
    calendar.set(Calendar.HOUR_OF_DAY, 0)
    calendar.set(Calendar.MINUTE, 0)
    calendar.set(Calendar.SECOND, 0)
    calendar.set(Calendar.MILLISECOND, 0)

    return calendar.timeInMillis
}

getSundayTime 以毫秒为单位返回星期日的时间

private fun getSundayTime(): Long {
    val calendar = Calendar.getInstance()
    calendar.timeInMillis = System.currentTimeMillis()
    calendar.firstDayOfWeek = Calendar.MONDAY
    calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)
    calendar.set(Calendar.HOUR_OF_DAY, 22)
    calendar.set(Calendar.MINUTE, 0)
    calendar.set(Calendar.SECOND, 0)
    calendar.set(Calendar.MILLISECOND, 0)

    return calendar.timeInMillis
}

我把所有的时间都放在了地方

fun generateWeek(): Week{
    val format = SimpleDateFormat("MMM d", Locale.ENGLISH)
    val mondayTime = getMondayTime()
    val sundayTime = getSundayTime()

    val label = "${format.format(mondayTime)} - ${format.format(sundayTime)}"
    return Week(label, mondayTime, sundayTime)
}

【问题讨论】:

  • 时区问题?如果您在周日(下午晚些时候或晚上?)在使用时区已经是周一的模拟器上运行代码,我想您会得到错误的观察周。
  • 考虑扔掉CalendarSimpleDateFormat 的课程。它们早已过时且设计不佳,SimpleDateFormat 特别是出了名的麻烦。相反,您可以将 ThreeTenABP 添加到您的 Android 项目中,以便使用现代 Java 日期和时间 API java.time。使用起来感觉好多了。

标签: android calendar android-calendar dayofweek java.util.calendar


【解决方案1】:

java.time

很抱歉我不会写 Kotlin(如果那是你的语言?)所以我必须相信你会从 Java 翻译过来。现代解决方案是:

    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MMM d", Locale.ENGLISH);
    // Time zone is crucial for controlling which week we get.
    ZoneId zone = ZoneId.of("America/Lower_Princes");
    WeekFields wf = WeekFields.ISO; // Monday is first day of week
    LocalDate today = LocalDate.now(zone);
    ZonedDateTime mondayTime = today.with(wf.dayOfWeek(), 1).atStartOfDay(zone);
    ZonedDateTime sundayTime = today.with(wf.dayOfWeek(), 7)
            .atTime(LocalTime.of(22, 0))
            .atZone(zone);
    String label = mondayTime.format(dateFormatter) + " - " + sundayTime.format(dateFormatter);
    System.out.println("Label:                 " + label);
    System.out.println("Monday time in millis: " + mondayTime.toInstant().toEpochMilli());
    System.out.println("Sunday time in millis: " + sundayTime.toInstant().toEpochMilli());

刚刚运行(星期一)这个打印出来的:

Label:                 Jun 18 - Jun 24
Monday time in millis: 1529294400000
Sunday time in millis: 1529892000000

在撰写本文时,太平洋极少数时区仍为星期日。所以我也尝试了其中一种:

    ZoneId zone = ZoneId.of("Pacific/Niue");

然后我上周得到了:

Label:                 Jun 11 - Jun 17
Monday time in millis: 1528714800000
Sunday time in millis: 1529312400000

因此,指定正确的时区对于获得所需的星期至关重要。我怀疑这是您问题中的问题:如果您的模拟器设置为使用运行代码时已经是星期一的时区,那么正如您所观察到的那样,它将给您下一周。

我正在使用并推荐 java.time,这是现代 Java 日期和时间 API。

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

是的,java.time 在较旧和较新的 Android 设备上运行良好。它只需要至少 Java 6

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

如果您反对依赖外部库,即使是像 ThreeTenABP 这样面向未来的库——我的意思是,它是由为 Java 开发 java.time 的同一个人开发的,它只包含也将包含在升级到 API 级别 26 或更高级别后的核心 Java — 在这种情况下,您可能可以通过将正确的 TimeZone 对象传递给 Calendar.getInstance(TimeZone) 方法来解决您的问题(我没有尝试过)。 TimeZone 是另一种过时的日期和时间类。

链接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-27
    • 1970-01-01
    • 1970-01-01
    • 2016-01-04
    • 2014-11-15
    • 1970-01-01
    相关资源
    最近更新 更多