【问题标题】:How to get days remaining of a date and print hours minutes and seconds Java8如何获取日期的剩余天数并打印小时分钟和秒Java 8
【发布时间】:2021-12-31 13:48:04
【问题描述】:

例如,我从服务器获取 UTC 日期

"endValidityDate": "2021-11-18T22:59:59Z"

我想知道从现在计算剩余天数的最佳方法是什么。

这是我现在得到的:

我从现在开始创建一个为期 2 天的日期:

DateTime.now().plusSeconds(172800)

我正在将其解析为 DateTimejoda,如果您这么说,我可以使用其他的。

当我在做不同的日子时,我是这样做的

val diff = endValidityDate.toDate().time - Date().time
val daysRemaining = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS)
return if (daysRemaining > 1) "$daysRemaining days}"
       else TimeUnit.DAYS.convert(diff, TimeUnit.SECONDS).toString()

我想要实现的场景是:

如果剩余天数超过一 (24 小时),则打印“剩余 2 天”,而不是显示“剩余 1 天”,然后添加一个计时器:

“0h 43m 3s”。

要做计时器,我只是用 now

减去剩余时间
val expireDate = LocalDateTime.now()
                   .plusSeconds(uiState.endValidityDate.timeLeft.toLong())
                   .toEpochSecond(ZoneOffset.UTC)
val currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)

然后在每一秒发生的时候,我都会像这样打印它:

val duration = Duration.ofSeconds(it)
binding.myTextView.text = String.format(
    "%02dh: %02dm: %02ds",
    duration.seconds / 3600,
    (duration.seconds % 3600) / 60,
    duration.seconds % 60,
)

但我没有得到 2 天,我只是得到一个输出:

00h: 33m: 50s

所以,我在这里遇到了一些问题:

这是最佳解决方案吗?如果不能,您能否描述一个更好的方法来实现我的目标? 为什么我的计时器显示为00h: 13m: 813s?我是在错误地执行正则表达式还是因为 epochSeconds?

实现

在尝试将其打印到设备时,给定来自服务器的 UTC 日期,那么它应该遵循此规则。

1.- 如果剩余天数大于 1 天,则打印“剩余 N 天”

2.- 如果剩余天数

  • 最少 1 位 (0h 2m 1s)
  • 最多 2 位数字(1h 23m 3s)

注意:

我正在使用 Java 8 如果这是问题所在,我还可以更改倒计时的方式以使用 millis 而不是 epochSeconds。

【问题讨论】:

  • 从Java 9开始就有Duration.toMinutesPart(),如果你使用的Java版本低于9,你必须自己计算部分,比如duration.toMinutes() % 60或类似的。
  • 你应该使用toMinutesPart()toSecondsPart()
  • @deHaar 抱歉,我完全忘了提及我使用的是哪个 Java,我使用的是 Java 8。
  • @deHaar 我已经用数学的东西改变了它,但仍然没有按预期显示,可能是因为我使用的是纪元秒数?

标签: java android date kotlin datetime


【解决方案1】:

您可以使用ZonedDateTime 来表示现在 和未来的日期时间,然后计算Duration.between,而不是先计算剩余秒数,然后再使用Duration.ofSeconds()

这是一个 Kotlin 示例:

fun main() {
    val utc = ZoneId.of("UTC")
    val now = ZonedDateTime.now(utc)
    val twoDaysFromNow = now.plusDays(2)
    
    val remaining = Duration.between(now, twoDaysFromNow)
    
    println(
        String.format("%02dh: %02dm: %02ds",
                        remaining.seconds / 3600,
                        (remaining.seconds % 3600) / 60,
                        remaining.seconds % 60
                     )
    )
}

输出:48h: 00m: 00s


如果您只对剩余全天感兴趣,请考虑使用ChronoUnit.DAYS.between,可能是这样的:

fun main() {
    val utc = ZoneId.of("UTC")
    val now = ZonedDateTime.now(utc)
    val twoDaysFromNow = now.plusDays(2)
    
    val remainingDays = ChronoUnit.DAYS.between(now, twoDaysFromNow)
    
    println(
        String.format("%d days", remainingDays)
    )
}

输出:2 days


补充:

由于我不清楚您尝试使用哪种数据类型来计算有效期结束前的剩余时间,您必须在在您的问题中提供更详细的信息或使用以下funs 之一:

传递ZonedDateTime

private fun getRemainingTime(endValidityDate: ZonedDateTime): String {
    // get the current moment in time as a ZonedDateTime in UTC
    val now = ZonedDateTime.now(ZoneId.of("UTC"))
    // calculate the difference directly
    val timeLeft = Duration.between(now, endValidityDate)
    // return the messages depending on hours left
    return if (timeLeft.toHours() >= 24) "${timeLeft.toDays()} days"
    else String.format("%02dh: %02dm: %02ds",
                        timeLeft.toHours(),
                        timeLeft.toMinutes() % 60,
                        timeLeft.toSeconds() % 60)
}

传递Instant

private fun getRemainingTime(endValidityDate: Instant): String {
    // get the current moment in time, this time as an Instant directly
    val now = Instant.now()
    // calculate the difference
    val timeLeft = Duration.between(now, endValidityDate)
    // return the messages depending on hours left
    return if (timeLeft.toHours() >= 24) "${timeLeft.toDays()} days"
    else String.format("%02dh: %02dm: %02ds",
                        timeLeft.toHours(),
                        timeLeft.toMinutes() % 60,
                        timeLeft.toSeconds() % 60)
}

直接传递String

private fun getRemainingTime(endValidityDate: String): String {
    // get the current moment in time as a ZonedDateTime in UTC
    val now = ZonedDateTime.now(ZoneId.of("UTC"))
    // parse the endValidtyDate String
    val then = ZonedDateTime.parse(endValidityDate)
    // calculate the difference
    val timeLeft = Duration.between(now, then)
    // return the messages depending on hours left
    return if (timeLeft.toHours() >= 24) "${timeLeft.toDays()} days"
    else String.format("%02dh: %02dm: %02ds",
                        timeLeft.toHours(),
                        timeLeft.toMinutes() % 60,
                        timeLeft.toSeconds() % 60)
}

【讨论】:

  • 感谢您的回答...我将 endVailidityTime 作为 DateTime 如何将其转换为 Temporal 以便能够使用 Duration.between?
  • 当我提出问题时,我从后端“2021-11-18T22:59:59Z”得到了这个,它是 UTC,然后我用我的解析器(Gson)转换为 DateTime,所以我需要知道如何将这个 expiryDateTime 作为 Duration.between 的参数传递
  • @StuartDTO 你不知道String吗?我的意思是,就像在你的例子中 "2021-11-18T22:59:59Z"... 你可以通过 ZonedDateTime.parse("2021-11-18T22:59:59Z") 将其设为 Temporal
  • 对于 GSON,看看您是否可以使用 ZonedDateTime,例如 here
  • 我的意思是我可以使用 Temporal api,但是可以使用另一个吗?或者那是因为这样做更简单?例如,是否可以使用 JodaTime 来做到这一点?还是即时?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
  • 1970-01-01
  • 1970-01-01
  • 2020-08-22
  • 1970-01-01
  • 2020-02-11
相关资源
最近更新 更多