Calculating TimeInMillis value for alternate days for the next 30 days gives me wrong dates in Kotlin

All we need is an easy explanation of the problem, so here it is.

I wanted to get the TimeInMillis value for alternate dates for the next 30 days from any selected date. I tried to get value for the dates using a for loop. But the code always returns the last 3 dates as wrong. Is there any alternate better way to get what i’m doing?

fun calculateDates(startDate: Long) {
        val singeDateDifference = 86400000
        val cancelledDates = arrayListOf<Long>()
            for (i in 2..30 step 2) {
                val difference = i * singeDateDifference
                cancelledDates.add(startDate + difference)
            }
}

The answer i’m getting for the above is this. I have logged the Long value as dates for better understanding.

startDate: 01/01/2022

[02/01/2022, 04/01/2022, 06/01/2022, 08/01/2022, 10/01/2022, 12/01/2022, 14/01/2022, 16/01/2022, 18/01/2022, 20/01/2022, 22/01/2022, 24/01/2022, 07/12/2021, 09/12/2021, 11/12/2021]

I’m always getting the last 3 dates from previous month. I can’t figure out what is wrong with the code.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

In the line

val difference = i * singeDateDifference

you are using integer types (Int in Kotlin), so for large enough results of your multiplication you will get an integer overflow (because Int.MAX_VALUE is 2147483647), which means that the result of the multiplication will be a negative value.
That happens for the last 3 difference values, which causes the last 3 dates to be 1 month behind.

Just ensure that the multiplication is done with Long types, one simple way to do that would be to set the date difference factor to Long.

// ensure we use Long when calculating with epoch millis
val singeDateDifference = 86400000L 

This will cause the multiplication to be performed with the Long values and the result will also be a Long value.
That will fix the bug and print the dates as you would expect.

In general cases time, dates and calendars are not easy to get right and years of work have been put into APIs such as the Time API.
When working with times and dates, my suggestion would be, to use the Time API classes and methods instead. They are in the package java.time (java.time.*).
The documentation is here: https://developer.android.com/reference/java/time/package-summary

That will prevent bugs like the one you had, because it allows you to work with higher-level concepts, such as .plusHours(24) or .plusDays(1) (which is not the same in all cases!) instead of doing all the calculations manually. Even if you have your own tests, sooner or later you will get something wrong with time, dates and calendars. Not all days are 24 hours long, shocking, I know 🙂 And this is just the first one on a long list of things that we believe about time, that are simply not true.

If you have to support older Android API levels (lower than 26) you need Android Gradle plugin of at least v4.0.0+ for the Time API to be available (support for core library desugaring).

If you cannot use that for some reason, add the JSR-310 Android Backport (ThreeTen ABP) as a dependency.
This will add the same Time API under the package org.threeten.bp.* with same classes and methods as the Time API, which is otherwise only available on Android from API level 26+ (without support for core library desugaring). Note that the recommended way is to switch to the newest version of the Android Gradle plugin, because this library’s support is winding down.

See here:
https://github.com/JakeWharton/ThreeTenABP

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

Leave a Reply