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)
Answer from Sam on Stack OverflowOne 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)
Here is a pure-Kotlin truncation function.
It uses Duration.toComponents() to get the constituent components of the duration. It then converts each back into a Duration, depending on whether it is equal to or larger than the requested DurationUnit.
import kotlin.time.*
import kotlin.time.DurationUnit.*
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.microseconds
import kotlin.time.Duration.Companion.nanoseconds
import kotlin.time.Duration.Companion.seconds
/**
* Truncates the duration to the specified [unit].
*
* Truncating the duration removes any time units smaller than the specified unit
* and returns a new [Duration] with the truncated value.
*
* @param unit The duration unit to truncate to.
* @returns a new [Duration] truncated to the specified [unit].
*/
private fun Duration.truncate(unit: DurationUnit): Duration {
return toComponents { days: Long, hours: Int, minutes: Int, seconds: Int, nanoseconds: Int ->
when (unit) {
NANOSECONDS -> this // there's no smaller unit than NANOSECONDS, so just return the current Duration
MICROSECONDS -> days.days + hours.hours + minutes.minutes + seconds.seconds + nanoseconds.nanoseconds.inWholeMicroseconds.microseconds
MILLISECONDS -> days.days + hours.hours + minutes.minutes + seconds.seconds + nanoseconds.nanoseconds.inWholeMilliseconds.milliseconds
SECONDS -> days.days + hours.hours + minutes.minutes + seconds.seconds
MINUTES -> days.days + hours.hours + minutes.minutes
HOURS -> days.days + hours.hours
DAYS -> days.days
}
}
}
Notes:
nanosecondsis documented as being less than1_000_000_000(1 second), so there's no need to convert it to seconds.- In order to round the nanoseconds to microseconds the
nanosecondsvalue is first converted to a duration (nanoseconds.nanoseconds), then rounded to microseconds (inWholeMicroseconds) and then converted to a duration (.microseconds). The same process is used to round nanoseconds to milliseconds.
Example
Here's an example usage demonstrates the truncate() function applied to a duration using different time units. Each truncation removes all time units smaller than the specified unit.
import kotlin.time.*
import kotlin.time.DurationUnit.*
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.microseconds
import kotlin.time.Duration.Companion.nanoseconds
import kotlin.time.Duration.Companion.seconds
fun main() {
// create a duration
val duration = 1.hours + 30.minutes + 45.seconds + 2.milliseconds + 3.microseconds + 5.nanoseconds
println(duration) // 1h 30m 45.002003005s
println(duration.truncate(NANOSECONDS)) // 1h 30m 45.002003005s (no truncation - can't go smaller than the smallest unit)
println(duration.truncate(MICROSECONDS)) // 1h 30m 45.002003s (no nanoseconds)
println(duration.truncate(MILLISECONDS)) // 1h 30m 45.002s (no milliseconds or nanoseconds)
println(duration.truncate(SECONDS)) // 1h 30m 45s (milliseconds and smaller are truncated)
println(duration.truncate(MINUTES)) // 1h 30m (seconds and smaller are truncated)
println(duration.truncate(HOURS)) // 1h (minutes and smaller are truncated)
println(duration.truncate(DAYS)) // 0s (all units are zeroed)
}
1h 30m 45.002003005s
1h 30m 45.002003005s
1h 30m 45.002003s
1h 30m 45.002s
1h 30m 45s
1h 30m
1h
0s
Run in Kotlin Playground
s = s.substring(0, Math.min(s.length(), 10));
Using Math.min like this avoids an exception in the case where the string is already shorter than 10.
Notes:
The above does simple trimming. If you actually want to replace the last characters with three dots if the string is too long, use Apache Commons
StringUtils.abbreviate; see @H6's solution. If you want to use the Unicode horizontal ellipsis character, see @Basil's solution.For typical implementations of
String,s.substring(0, s.length())will returnsrather than allocating a newString.This may behave incorrectly1 if your String contains Unicode codepoints outside of the BMP; e.g. Emojis. For a (more complicated) solution that works correctly for all Unicode code-points, see @sibnick's solution.
1 - A Unicode codepoint that is not on plane 0 (the BMP) is represented as a "surrogate pair" (i.e. two char values) in the String. By ignoring this, we might trim the string to fewer than 10 code points, or (worse) truncate it in the middle of a surrogate pair. On the other hand, String.length() is not the correct measure for Unicode text length, so trimming based on that property may be the wrong thing to do.
StringUtils.abbreviate from Apache Commons Lang library could be your friend:
StringUtils.abbreviate("abcdefg", 6) = "abc..."
StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
StringUtils.abbreviate("abcdefg", 4) = "a..."
Commons Lang3 even allow to set a custom String as replacement marker. With this you can for example set a single character ellipsis.
StringUtils.abbreviate("abcdefg", "\u2026", 6) = "abcde…"
The KDoc of Double.toInt() is simply inherited from Number.toInt(), and for that, the exact meaning is, it is defined in the concrete Number implementation how it is converted to Int.
In Kotlin, the Double operations follow the IEEE 754 standard, and the semantics of the Double.toInt() conversion is the same as that of casting double to int in Java, i.e. normal numbers are rounded toward zero, dropping the fractional part:
println(1.1.toInt()) // 1
println(1.7.toInt()) // 1
println(-2.3.toInt()) // -2
println(-2.9.toInt()) // -2
use this roundToInt() in kotlin
import kotlin.math.roundToInt
fun main() {
var r = 3.1416
var c:Int = r.roundToInt()
println(c)
}
Use List.subList:
import java.util.*;
import static java.lang.Math.min;
public class T {
public static void main( String args[] ) {
List<String> items = Arrays.asList("1");
List<String> subItems = items.subList(0, min(items.size(), 2));
// Output: [1]
System.out.println( subItems );
items = Arrays.asList("1", "2", "3");
subItems = items.subList(0, min(items.size(), 2));
// Output: [1, 2]
System.out.println( subItems );
}
}
You should bear in mind that subList returns a view of the items, so if you want the rest of the list to be eligible for garbage collection, you should copy the items you want to a new List:
List<String> subItems = new ArrayList<String>(items.subList(0, 2));
If the list is shorter than the specified size, expect an out of bounds exception. Choose the minimum value of the desired size and the current size of the list as the ending index.
Lastly, note that the second argument should be one more than the last desired index.
list.subList(100, list.size()).clear();
or:
list.subList(0, 100);
According to the docs: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim.html
fun String.trim(): String Returns a string having leading and trailing whitespace removed.
The it <= ' ' would remove all the 'non printable' characters with ascii code less or equal than space (ascii decimal = 32) as carriage return, line feed...
I've just tested with many of this characters:
val kotlin = "\t\t"
println(kotlin)
val kotlin2 = "\t\t".trim()
println(kotlin2)
val kotlin3 = "\t\t".trim{it <= ' '}
println(kotlin3)
this outputs:
They both clean this characters. And as @AlexeyRomanov states kotlin understands as a whitespace character the ones that return true using the isWhitespace method. So the it <= ' ' is to make it only trim the same chars as java does and not the other whitespace characters according to the Unicode standard.
If we test for example the \u00A0 character:
val kotlin4 = "\u00A0\u00A0".trim()
println(kotlin4)
val kotlin5 = "\u00A0\u00A0".trim{it <= ' '}
println(kotlin5)
we can see the difference in output:
You can test it in the kotlin playground.
Java's trim documentation says
Otherwise, if there is no character with a code greater than '\u0020' in the string, then a String object representing an empty string is returned.
Otherwise, let k be the index of the first character in the string whose code is greater than '\u0020', and let m be the index of the last character in the string whose code is greater than '\u0020'. A String object is returned, representing the substring of this string that begins with the character at index k and ends with the character at index m-that is, the result of this.substring(k, m + 1).
So the condition is exactly { it <= ' ' } (where it is a character in the string).
Kotlin instead uses
public fun CharSequence.trim(): CharSequence = trim(Char::isWhitespace)
which is true e.g. for non-breaking space \u00A0, Ogham space mark \u1680, etc. and false for some characters below ' ' (e.g. \u0001).