当目标 Android API < 26 时,Duration.between 的最佳替代方案是什么?

What's the best alternative for Duration.between when targetting Android API < 26?

目前,我继续修补我的一个宠物项目的功能。 我决定包含阻止用户执行某些操作的功能 action/s 并显示横幅以显示冷却时间。

例如

鉴于:从 2019 年 11 月 19 日 2:00:00 上午 (1574128800) 到 2019 年 11 月 21 日 6:32:00 下午 (1574361120),用户因执行某些 action/s 而被阻止。

输出:2 days 16 hours 32 minutes

这就是我现在的方法。不幸的是,它只适用于 Android API >= 26.

/**
 * If using for Android, `Duration` requires API > 26
 * @param start Epoch time in milliseconds
 * @param end Epoch time in milliseconds
 */
fun getReadableBetween(start: Long, end: Long): String {
    val startDate = Date(start)
    val endDate = Date(end)
    var duration = Duration.between(startDate.toInstant(), endDate.toInstant())

    val days = duration.toDays()
    duration = duration.minusDays(days)
    val hours = duration.toHours()
    duration = duration.minusHours(hours)
    val minutes = duration.toMinutes()

    val stringBuilder = StringBuilder()

    if (days != 0L) {
        stringBuilder.append(days)
        if (days == 1L) {
            stringBuilder.append(" day ")
        } else {
            stringBuilder.append(" days ")
        }
    }

    if (hours != 0L) {
        stringBuilder.append(hours)
        if (hours == 1L) {
            stringBuilder.append(" hour ")
        } else {
            stringBuilder.append(" hours ")
        }
    }


    if (minutes != 0L) {
        stringBuilder.append(minutes)
        if (minutes == 1L) {
            stringBuilder.append(" minute.")
        } else {
            stringBuilder.append(" minutes.")
        }
    }

    println("Breakdown:")
    println("Days: $days")
    println("Hours: $hours")
    println("Minutes: $minutes")

    return stringBuilder.toString()
}

尽管我很想使用 3rd 方库,但我想亲自动手使用开箱即用的日期和时间 API 基础知识。

PS。在将此链接到其他 SO 帖子之前,请考虑场景。

决定为 Android API < 26 创建遗留功能。

/**
 * If using for Android & API < 26
 * @param start Epoch time in milliseconds
 * @param end Epoch time in milliseconds
 */
fun getReadableBetweenLegacy(start: Long, end: Long): String {
    val startDate = Date(start)
    val endDate = Date(end)
    val calendar = Calendar.getInstance()
    val diff = endDate.time - startDate.time
    calendar.timeInMillis = diff

    val daySeconds = 1000 * 60 * 60 * 24
    val hourSeconds = 1000 * 60 * 60
    val days = diff / daySeconds
    val hours = ((diff - (daySeconds * days)) / (hourSeconds));
    val minutes = (diff - (daySeconds * days) - (hourSeconds * hours)) / (1000 * 60)

    val stringBuilder = StringBuilder()
    if (days != 0L) {
        stringBuilder.append(days)
        if (days == 1L) {
            stringBuilder.append(" day ")
        } else {
            stringBuilder.append(" days ")
        }
    }

    if (hours != 0L) {
        stringBuilder.append(hours)
        if (hours == 1L) {
            stringBuilder.append(" hour ")
        } else {
            stringBuilder.append(" hours ")
        }
    }


    if (minutes != 0L) {
        stringBuilder.append(minutes)
        if (minutes == 1L) {
            stringBuilder.append(" minute.")
        } else {
            stringBuilder.append(" minutes.")
        }
    }

    println("Breakdown:")
    println("Days: $days")
    println("Hours: $hours")
    println("Minutes: $minutes")

    return stringBuilder.toString()
}

解决方案非常简单,几乎没有误差。

如果您使用的是 Gradle 插件 4.0 或更高版本(使用 Android Studio 4.0 或更高版本),您可以利用 D8 核心库脱糖。这包括 java.time 中的一部分功能,并允许您在项目中使用 java.time.Duration;即使您需要支持早于 API 26.

的版本

在您模块的 build.gradle 文件中:

android {

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
        coreLibraryDesugaringEnabled true
    }

    // If using Kotlin
    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8
    }
}
dependencies {
    …
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.5'
}

您现在应该可以使用此 class 错误。

一些来源: