Last active
February 3, 2021 06:43
-
-
Save maulikhirani/01e1ae1c023ca7f6e3bdf6ba392cf400 to your computer and use it in GitHub Desktop.
Format Date-Time Duration in words with Kotlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Number of milliseconds in a standard second. | |
*/ | |
const val MILLIS_PER_SECOND: Long = 1000 | |
/** | |
* Number of milliseconds in a standard minute. | |
*/ | |
const val MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND | |
/** | |
* Number of milliseconds in a standard hour. | |
*/ | |
const val MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE | |
/** | |
* Number of milliseconds in a standard day. | |
*/ | |
const val MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR | |
/** | |
* Helper class for Duration formatting in words | |
* | |
* @property durationInMills difference between two times in milliseconds | |
*/ | |
class DateTimeDurationHelper(private var durationInMills: Long) { | |
constructor(startMills: Long, endMills: Long) : this( | |
if (startMills > endMills) { | |
startMills - endMills | |
} else { | |
endMills - startMills | |
} | |
) | |
init { | |
if (durationInMills < 0) { | |
durationInMills = -durationInMills | |
} | |
} | |
val days: Long = durationInMills / MILLIS_PER_DAY | |
val hours: Long = (durationInMills - (days * MILLIS_PER_DAY)) / MILLIS_PER_HOUR | |
val minutes: Long = | |
(durationInMills - (days * MILLIS_PER_DAY) - (hours * MILLIS_PER_HOUR)) / MILLIS_PER_MINUTE | |
val seconds: Long = | |
(durationInMills - (days * MILLIS_PER_DAY) - (hours * MILLIS_PER_HOUR) - | |
(minutes * MILLIS_PER_MINUTE)) / MILLIS_PER_SECOND | |
/** | |
* Formats the duration as string (i.e 1 day, 2 hours, 3 minutes, 20 seconds) | |
* | |
* Note: this function doesn't support units like week, month, or year. The maximum unit is 'day' | |
* | |
* @param separator between different duration units (default is comma ", ") | |
* @param lowestDurationUnit decides what should be the lowest unit in the duration, | |
* For example, if you set this value as MINUTE, the formatted duration won't include seconds | |
* @param durationLength decides maximum number of non-zero units to be returned. For example, | |
* if you set this as FIRST_TWO, and your actual duration is "0 days, 1 hour, 2 minutes, 3 seconds", | |
* it will return "1 hour, 2 minutes" as result | |
* @param durationFormatter decides different ways to describe the duration units, | |
* If set as FULL, the units will be written as "day(s), hour(s), minute(s), second(s)" | |
* If set as SHORT, the units will be written as "day(s), hr(s), min(s), sec(s)" | |
* @return | |
*/ | |
fun durationInWords( | |
separator: String = ", ", | |
lowestDurationUnit: DurationUnit = DurationUnit.MINUTE, | |
durationLength: DurationLength = DurationLength.FULL, | |
durationFormatter: DurationFormatter = DurationFormatter.FULL | |
): String { | |
val daysPart = days.duration(DurationUnit.DAY, durationFormatter) | |
val hoursPart = hours.duration(DurationUnit.HOUR, durationFormatter) | |
val minutesPart = minutes.duration(DurationUnit.MINUTE, durationFormatter) | |
val secondsPart = seconds.duration(DurationUnit.SECOND, durationFormatter) | |
var list = listOf(daysPart, hoursPart, minutesPart, secondsPart) | |
list = when (lowestDurationUnit) { | |
DurationUnit.DAY -> list.dropLast(3) | |
DurationUnit.HOUR -> list.dropLast(2) | |
DurationUnit.MINUTE -> list.dropLast(1) | |
else -> list | |
} | |
list = list.dropWhile { it.startsWith("0") }.dropLastWhile { it.startsWith("0") } | |
if (durationLength == DurationLength.FIRST_TWO) { | |
list = list.take(2).dropLastWhile { it.startsWith("0") } | |
} else if (durationLength == DurationLength.FIRST_THREE) { | |
list = list.take(3).dropLastWhile { it.startsWith("0") } | |
} | |
var durationString = list.joinToString(separator) | |
if (list.isEmpty()) { | |
durationString = 0L.duration(lowestDurationUnit, durationFormatter) | |
} | |
return durationString | |
} | |
private fun Long.duration( | |
durationUnit: DurationUnit, | |
durationFormatter: DurationFormatter | |
): String { | |
var duration = "$this ${durationUnit.getFormattedDurationUnit(durationFormatter)}" | |
if (this != 1L) { | |
duration = duration.plus("s") | |
} | |
return duration | |
} | |
private fun DurationUnit.getFormattedDurationUnit(durationFormatter: DurationFormatter): String { | |
return when (durationFormatter) { | |
DurationFormatter.FULL -> { | |
when (this) { | |
DurationUnit.DAY -> "day" | |
DurationUnit.HOUR -> "hour" | |
DurationUnit.MINUTE -> "minute" | |
DurationUnit.SECOND -> "second" | |
} | |
} | |
DurationFormatter.SHORT -> { | |
when (this) { | |
DurationUnit.DAY -> "day" | |
DurationUnit.HOUR -> "hr" | |
DurationUnit.MINUTE -> "min" | |
DurationUnit.SECOND -> "sec" | |
} | |
} | |
} | |
} | |
enum class DurationLength { | |
FULL, | |
FIRST_TWO, | |
FIRST_THREE | |
} | |
enum class DurationFormatter { | |
FULL, | |
SHORT | |
} | |
enum class DurationUnit { | |
DAY, | |
HOUR, | |
MINUTE, | |
SECOND, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment