How to get the difference betweeen two dates (jetpack compose/kotlin)? - kotlin

I have to calculate how many days are left between the date selected by the user through a DatePicker and the current date
I was trying to write something like this:
val simpleDate = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
val date = simpleDate.parse(event!!.date!!)
val diff = Duration.between(LocalDate.now(), date.toInstant())
val leftDays = diff.toDays()

Your mix of outdated (SimpleDateFormat, 'Date') and modern (LocalDate) APIs is not optimal, I think:
I would use plain java.time here, because…
you can obviously use it in your application
it has a specific class for datetime Strings of the pattern you have shown in your question: an OffsetDateTime and
there's a java.time.Duration which you have tried to use
Here's an example:
fun main(args: Array<String>) {
// example input, some future datetime
val input = "2022-12-24T13:22:51.837Z"
// parse that future datetime
val offsetDateTime = OffsetDateTime.parse(input)
// build up a duration between the input and now, use the same class
val duration = Duration.between(OffsetDateTime.now(), offsetDateTime)
// get the difference in full days
val days = duration.toDays()
// print the result as "days left"
println("$days days left")
}
Output:
110 days left
If you don't receive a datetime but a date without time (just day of month, month of year and year), then use a LocalDate and calculate the ChronoUnit.DAYS.between(today, futureDate)
fun main(args: Array<String>) {
// example input, some future date
val input = "2022-12-24"
// parse that
val futureDate = LocalDate.parse(input)
// get the difference in full days
val days = ChronoUnit.DAYS.between(LocalDate.now(), futureDate)
// print the result
println("$days days left")
}
Output (again):
110 days left

Try below code -
val previousTimeDouble: Double = previousTime.toDouble()
val nowTimeDouble: Double = System.currentTimeMillis().toDouble()
val dateNowString: String = dateNow.toString();
val time: Long = (nowTimeDouble - previousTimeDouble).toLong()
val difference: String= differenceBetweenTwoTimes(time)
Log.d("difference", difference)
Function for converting time difference into units -
fun differenceBetweenTwoTimes(time: Long): String {
var x: Long = time / 1000
var seconds = x % 60
x /= 60
var minutes = x % 60
x /= 60
var hours = (x % 24).toInt()
x /= 24
var days = x
return String.format("%02d:%02d:%02d", hours, minutes, seconds)
}

Related

Kotlin: Phone Bill calculator

I'm new at kotlin. Now I'm trying to code a Phone Bill Calculator, when I have to charge user 0.25 for every minute they were over their plan, and 15% tax on subtotal. I can't find the 15% tax.
import java.util.*
fun main(args: Array<String>) {
var numberOfCalls: Int
val phoneBill: Float
val thetax: Float = 15f
val scan = Scanner(System.`in`)
print("Enter the Total Minutes of Calls Made this Month: ")
numberOfCalls = scan.nextInt()
if (numberOfCalls <= 60) phoneBill = 10f else {
numberOfCalls = numberOfCalls - 60
phoneBill = ((10 + (numberOfCalls * 0.25 )).toFloat() + (thetax/100))
}
println("\nTelephone Bill this Month = $phoneBill")
}
Instead of using this formula bill = total + total * tax you was using this bill = total + taxPercentage which is wrong, you can calculate it like that and have theTaxAmount separately ( you can use it somewhere ):
fun main(args: Array<String>) {
var numberOfCalls: Int
val phoneBill: Float
val theTaxPercentage: Float = 0.15f
val scan = Scanner(System.`in`)
print("Enter the Total Minutes of Calls Made this Month: ")
numberOfCalls = scan.nextInt()
if (numberOfCalls <= 60) phoneBill = 10f else {
numberOfCalls -= 60
val phoneBillWithoutTax = (10 + (numberOfCalls * 0.25 )).toFloat()
val theTaxAmount = phoneBillWithoutTax * theTaxPercentage
phoneBill = phoneBillWithoutTax + theTaxAmount
}
println("\nTelephone Bill this Month = $phoneBill")
}
Your algebra error is that you didn't multiply the tax by anything. You just added it like it was a flat rate of 15 cents. A tax by percentage is multiplied by the total amount. And an algebra tip: it's less math (and less code) to multiply something by 115% (1.15) than it is to figure out what 15% would be and add it to the original value.
I find it is easier (and has clearer code) to solve a problem by doing minimal number of steps at a time instead of setting up all your variables at the start and then modifying them. Create/initialize what you need only immediately before you will use it. Basically, if you can write your logic out of vals and no vars, usually this will be a cleaner solution.
fun main(args: Array<String>) {
print("Enter the Total Minutes of Calls Made this Month: ")
val scan = Scanner(System.`in`)
val numberOfMinutes = scan.nextInt()
var excessMinutes = numberOfMinutes - 60
if (excessMinutes < 0) {
excessMinutes = 0
}
val bill = 10 + excessMinutes * 0.25
val taxedBill = bill * 1.15
println("\nTelephone Bill this Month = $taxedBill")
}
The four lines of code for excessMinutes can be shortened as below, but I wrote it out verbosely since you are just learning how the basic logic works, and if you're doing this for a class, the teacher might not expect you to be using helper functions like that yet.
val excessMinutes = max(0, numberOfMinutes - 60)

How can I truncate a Kotlin Duration?

Java's Duration has a truncate function.
Duration d = myDuration.truncatedTo(ChronoUnit.SECONDS);
public Duration truncatedTo​(TemporalUnit unit)
Returns a copy of this Duration truncated to the specified unit.
Truncating the duration returns a copy of the original with conceptual fields smaller than the specified unit set to zero. For example, truncating with the MINUTES unit will round down to the nearest minute, setting the seconds and nanoseconds to zero.
However Kotlin has a different implementation for Duration, and this does not have an analogous truncation method.
I want to be able to divide or multiply a Duration by some number, and then (with an extension function) remove any time unit smaller than the one I supply.
import kotlin.time.*
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes
fun main() {
val duration = 10.days + 5.hours + 33.minutes
println(duration)
val divided = duration / 100.001
println(divided)
val truncatedToSeconds = divided.truncate(DurationUnit.SECONDS)
println(truncatedToSeconds) // expect: 2h 27m 19s
val truncatedToMinutes = divided.truncate(DurationUnit.MINUTES)
println(truncatedToMinutes) // expect: 2h 27m
val truncatedToHours = divided.truncate(DurationUnit.HOURS)
println(truncatedToHours) // expect: 2h
}
fun Duration.truncate(unit: DurationUnit): Duration {
/// ...
return this
}
One option is to convert it to a Long and back again, using your desired unit:
fun Duration.truncate(unit: DurationUnit): Duration =
toLong(unit).toDuration(unit)

For loop must have an iterator()

I need this service in which if the person stays for longer than 30 minutes, they have to pay an extra $10 every 15 minutes (and for the fraction of the 15 as well).
I designed it like this so far:
var checkInTime: Calendar
val totalTime: Long
get() = (Calendar.getInstance().timeInMillis - checkInTime.timeInMillis) / MIN_IN_MILISEC
fun getTime(totalTime:Long): Int{
var finalPrice = 0
var initialPrice = 20
if(totalTime<31){
finalFee = initialPrice
} else {
val extraPrice = 10
val extraTime = 15
finalFee = initialPrice
for(extraTime in totalTime){
finalFee += extraTime
}
return finalFee
}
I get the error "For loop must have an iterator()" when I try to loop through the totalTime when it's more than 30 minutes so that I can add $10 every 15 extra minutes. I need some help as to how to add to the finalFee every extra 15 minutes the person stays since my method is not working.
Thank you.
Let's take a look at your getTime function:
You're using a Long as totalTime. You can measure it in minutes to simplify your calculation (since all time values are measured in minutes). Since a Long type in Kotlin stores a integer up to 9,223,372,036,854,775,807 and no soul on Earth will use your service for that long (this represents 17 billion milleniums), you can just use an Int.
You're not declaring the finalFee variable, thus the code will raise an
"Unresolved reference" error. Since you're not using the finalPrice variable, I'm assuming you wanted to use this instead.
You're trying to iterate over a numeric value (in this case, totalTime, which is a Long). You can iterate over each element of a List, but how would you iterate over each element of an integer? I'm assuming you want to do a certain action totalTime number of times. In this case, you would use ranges.
You're also not using the variables extraPrice and extraTime.
There's code that's common to both if-else conditions (finalPrice = initialPrice), so you can extract that to outside the if-statement.
Refactoring your function:
fun getTime(totalTime: Int): Int {
var finalPrice = 20
if (totalTime >= 30) {
(0 until totalTime).forEach {
finalPrice += 15
}
}
return finalPrice
}
It's shorter, but still doesn't do what it's supposed to: let's suppose totalTime is equal to 45. The person got 30 minutes costing $20 and only have to pay $10 for every 15 minutes, therefore will only pay $30 total. Your function is considering that the person will have to pay $15 for every minute they stayed, because it uses a for-loop that goes from 0 to totalTime. For that, you need a for-loop that goes from 30 (the time limit) from the total time (the totalTime) every 15 minutes:
fun getTime(totalTime: Int): Int {
var finalPrice = 20
if (totalTime > 30) {
(30 until totalTime step 15).forEach {
finalPrice += 10
}
}
return finalPrice
}
Better yet, you don't even need a for-loop, you can just use maths:
fun getTime(totalTime: Int): Int {
var finalPrice = 20
if (totalTime > 30) {
finalPrice += ((totalTime - 30) / 15) * 10
// ^^^^^^^^^^^^^^^^ Get the exceeding time
// ^^^^^^^^^^^^^^^^^^^^^^^ How many 15 minutes are there?
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Put $10 for every 15 minutes
}
return finalPrice
}
The last part: your question said you need to consider the fraction of 15 as well. Therefore, you need to use a real value, not an integer. Let's change it to a Double:
fun getTime(totalTime: Int): Double {
var finalPrice = 20.0
if (totalTime > 30) {
finalPrice += ((totalTime - 30) / 15.0) * 10
}
return finalPrice
}
Let's test your function:
fun main() {
println(getTime(0)) // Outputs 20.0
println(getTime(10)) // Outputs 20.0
println(getTime(30)) // Outputs 20.0
println(getTime(45)) // Outputs 30.0
println(getTime(60)) // Outputs 40.0
println(getTime(70)) // Outputs 46.666...
}

Group numbers into different ranges

I'm new to Kotlin and I'm trying to solve some problem.
I have a list with the following object:
data class Route(duration: Int)
I want to create a map that will group those trips according to the range of the duration (e.g. 0-9 are single group, 10-19 the next, 20-29, and so on...)
for example, the result of this list:
listOf(Route(5), Route(7), Route(31))
should be the following map:
0..9 to listOf(Route(5), Route(7))
30..39 to listOf(Route(31))
I searched and I've seen that I can put the range into groupBy - however, this is a const range. how can I group by different ranges?
You can use the groupBy function to do that.
fun createRangeOfTen(number: Int): IntRange {
val trunc = number / 10
val lowerBound = trunc * 10
val upperBound = lowerBound + 9
return lowerBound..upperBound
}
val list = listOf(
Route(5), Route(7), Route(31)
)
val map = list.groupBy({ createRangeOfTen(it.duration) }, { it })
println(map)
// {0..9=[Route(duration=5), Route(duration=7)], 30..39=[Route(duration=31)]}

Format a number to string, fill 0 when it's not enough two characters

I want to format the number to String and fill 0 when it's not enough two characters
fun formatDuration(val duration):String {
val minutes = duration.toInt() / 60
return "$minutes"
}
For example, if minutes is 6, it should displayed 06 rather than 6.
You can padStart the toString() result of minutes.
I tried your code in the Kotlin Playground and it wasn't compilable / runnable. For the following example, I had to change parts of your fun:
fun main() {
println(formatDuration(364.34))
}
fun formatDuration(duration: Double): String {
val minutes = duration.toInt() / 60
// fill the result to be of 2 characters, use 0 as padding char
return minutes.toString().padStart(2, '0')
}
Executing this results in the output 06.
Alternatively, you can simply use String.format() from Java, just
return "%02d".format(minutes)
instead of return minutes.toString().padStart(2, '0'), the result stays the same.
You can achive this with padStart
Example:
val padWithSpace = "125".padStart(5)
println("'$padWithSpace'") // ' 125'
val padWithChar = "a".padStart(5, '.')
println("'$padWithChar'") // '....a'
// string is returned as is, when its length is greater than the specified
val noPadding = "abcde".padStart(3)
println("'$noPadding'") // 'abcde'