Skip to content

Instantly share code, notes, and snippets.

@esabook
Created March 16, 2021 15:23
Show Gist options
  • Save esabook/51477179a995ea935149d15035b1f5a8 to your computer and use it in GitHub Desktop.
Save esabook/51477179a995ea935149d15035b1f5a8 to your computer and use it in GitHub Desktop.
[Kotlin-JVM] Custom monthNames, relativeDate, stringToDate, DateToString
package *
import android.text.format.DateUtils
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit.MILLISECONDS
import kotlin.math.abs
object DateFormatUtils {
val DEFAULT_FROM_DATE_PATTERN = "yyyy-MM-dd"
val DEFAULT_FROM_DATE_PATTERN_LONG = "yyyy-MM-dd HH:mm:ss"
val DEFAULT_TO_DATE_PATTERN = "yyyy MMM dd"
val longMonthNamesIndo = arrayOf(
"Januari",
"Februari",
"Maret",
"April",
"Mei",
"Juni",
"Juli",
"Agustus",
"September",
"Oktober",
"November",
"Desember"
)
val shortMonthNamesIndo = arrayOf(
"Jan",
"Feb",
"Mar",
"Apr",
"Mei",
"Jun",
"Jul",
"Agu",
"Sep",
"Okt",
"Nov",
"Des"
)
/**
*
*/
fun String.localizeDate(fromPatter: String = DEFAULT_FROM_DATE_PATTERN, toPattern: String = DEFAULT_TO_DATE_PATTERN): String {
return try {
val sdf = SimpleDateFormat(toPattern, Locale.getDefault())
val dfs = sdf.dateFormatSymbols
dfs.months = longMonthNamesIndo
dfs.shortMonths = shortMonthNamesIndo
sdf.dateFormatSymbols = dfs
val date = this.toDateOrNull(fromPatter)
return sdf.format(date)
} catch (ignored: Exception) {
this
}
}
fun String?.localizeDate(targetPattern: String, vararg fromPattern: String): String? {
return this?.toDateOrNull(*fromPattern)
.takeIf { it != null }
?.toString(targetPattern, true)
?: this
}
/**
* 1. dibawah 1 jam, tampilin menit (contoh: 59 menit yang lalu)
* 2. dibawah <24 jam, tampilin per jam (contoh 2 jam yang lalu). Kalau 1 jam 29 menit itu 1 jam, 1 jam 30 menit itu 2 jam
* 3. dibawah 1 minggu, hari (contoh kemarin, 2 hari yang lalu, 5 hari yang lalu)
* 4. diatas 1 minggu, tanggal (contoh 11 Mei)
* 5. beda tahun, DD MMM YYYY (contoh 11 Mei 2020)
*/
fun Date.relativeLocalizeDate(): String {
val milliseconds = time - System.currentTimeMillis()
val positiveValue = abs(milliseconds)
val now = Date().time
val prePostSuffix = if (time > now) "lagi" else "yang lalu"
return when {
this.year != Date().year -> toString("dd MMM yyyy", true)
positiveValue > DateUtils.WEEK_IN_MILLIS -> toString("dd MMM", true)
positiveValue > DateUtils.DAY_IN_MILLIS -> "${MILLISECONDS.toDays(positiveValue)} hari $prePostSuffix"
positiveValue > DateUtils.HOUR_IN_MILLIS -> "${abs((MILLISECONDS.toMinutes(positiveValue) / 90).toInt()) + 1} jam $prePostSuffix"
positiveValue > DateUtils.MINUTE_IN_MILLIS -> "${MILLISECONDS.toMinutes(positiveValue)} menit $prePostSuffix"
else -> "Baru saja"
}
}
/**
* we have nonStandard format if 10:30:30+07:00 from hh:mm:ssXXX
* should read as 03:30:30
*
* Example:
* ```
* val publishAtDateFormat = arrayOf(
* "yyyy-MM-dd HH:mm:ss",
* "yyyy-MM-dd'T'HH:mm:ss.SS'Z'",
* "yyyy-MM-dd'T'HH:mm:ssXXX",
* "yyyy-MM-dd'T'HH:mm:ss'Z'",
* "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
* "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
* "yyyy-MM-dd'T'HH:mm:ss:SS'Z'")
*
* dateInString.toDateOrNull(*publishAtDateFormat)
* ```
*/
fun String.toDateOrNull(vararg pattern: String, minusGMT: Boolean = false): Date? {
if (this.isEmpty()) return null
pattern.asList().forEach {
try {
return SimpleDateFormat(it, Locale.getDefault()).parse(this)?.apply {
if (!minusGMT) return@apply
val calendar = Calendar.getInstance()
calendar.time = this
time -= calendar.get(Calendar.ZONE_OFFSET)
}
} catch (ignored: Exception) {
}
}
return null
}
/**
* Example:
* ```publishDate.toString("dd MMM yyyy", true)```
*/
fun Date.toString(pattern: String, isLocalized: Boolean = false): String {
return try {
if (isLocalized)
toString(DEFAULT_FROM_DATE_PATTERN_LONG).localizeDate(DEFAULT_FROM_DATE_PATTERN_LONG, pattern)
else
SimpleDateFormat(pattern, Locale.getDefault()).format(this)
} catch (ignored: Exception) {
this.toString()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment