I’m getting from server an UTC date for instance
"endValidityDate": "2021-11-18T22:59:59Z"
I’d like to know what is the optimal way to calculate remaining days from now.
Here’s what I got now :
I’m creating a date for 2 days from now as :
DateTime.now().plusSeconds(172800)
I’m parsing it to a DateTime
joda I can use other if you say so.
When doing the diff of days I’m doing this way
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()
The scenario that I’m trying to achieve is :
If the days remaining is more than one (24h) then print “2 days remaining” for instance, and instead of showing “1 day remaining” then just add a timer as :
“0h 43m 3s”.
To do the timer I’m just subtracting the time remaining with now
val expireDate = LocalDateTime.now() .plusSeconds(uiState.endValidityDate.timeLeft.toLong()) .toEpochSecond(ZoneOffset.UTC) val currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)
And then on every second it happen I print it like this :
val duration = Duration.ofSeconds(it) binding.myTextView.text = String.format( "%02dh: %02dm: %02ds", duration.seconds / 3600, (duration.seconds % 3600) / 60, duration.seconds % 60, )
But I’m not getting the 2 days, I’m just getting as an output :
00h: 33m: 50s
So, I’m having some problems here for instance :
Is this an optimal solution? If not could you describe a better one where I can achieve my goal?
Why my timer is showing with 00h: 13m: 813s
? Am I doing the regex incorrectly or it’s because of epochSeconds?
To achieve
Given an UTC date from server when trying to print it to the device then it should follow this rules.
1.- If days remaining is > than 1 day then print “N days remaining”
2.- If days remaining is <= 1 then print a timer (it’s already done, the thing is how to print it correctly).
- Minimum 1 digit (0h 2m 1s)
- Maximum 2 digits (1h 23m 3s)
Note :
I’m using Java 8 I can change also the way I’m doing the countdown to use millis instead of epochSeconds if that’s the problem.
Advertisement
Answer
You could do that using a ZonedDateTime
for now and the future datetime, and then calculate a Duration.between
instead of calculating remaining seconds first and then use a Duration.ofSeconds()
.
Here`s a Kotlin example:
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 ) ) }
Output: 48h: 00m: 00s
If you are interested in remaining full days only, then consider using ChronoUnit.DAYS.between
, maybe like this:
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) ) }
Output: 2 days
Additional:
Since it is unclear to me what data type you are trying to use for the calculation of the time left until end of validity, you will have to choose between providing more detailed information in your question or using one of the following fun
s:
Pass a 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) }
Pass an 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) }
Pass the String
directly
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) }