androidkotlinjava-timekotlinx-datetime

How can you format a kotlinx-datetime LocalDateTime?


I'm converting some code from using Java 8's LocalDatetime to using the version from kotlinx-datetime and I can't find any formatting methods. Specifically, I'm replacing a FormatStyle.MEDIUM. Do they not exist and I need to write the formatting?

This is for an Android app. Is there are there Android specific libraries I can use? Or can I do this with pre-Java 8 methods to maintain support for older versions of Android?

Edit: I posted my current solution as an answer. My requirements have changed since I asked this question. It also needs to support JVM and iOS. JS and localization are a big bonus. I'd like to see a solution that supports localization without using platform-specific code.


Solution

  • My current implementation utilizes expect/actual to support Java, iOS, and JS.

    Common:

    expect fun Instant.toDateTimeString(formatStyle: FormatStyle, timeZone: TimeZone = TimeZone.currentSystemDefault()): String
    
    enum class FormatStyle {
        SHORT,
        MEDIUM,
        LONG,
    }
    

    Java/Android:

    actual fun Instant.toDateTimeString(formatStyle: FormatStyle, timeZone: TimeZone): String {
        val javaFormatStyle = when (formatStyle) {
            FormatStyle.SHORT -> java.time.format.FormatStyle.SHORT
            FormatStyle.MEDIUM -> java.time.format.FormatStyle.MEDIUM
            FormatStyle.LONG -> java.time.format.FormatStyle.LONG
        }
        val zonedTime = toJavaInstant().atZone(timeZone.toJavaZoneId())
        val formatter = DateTimeFormatter.ofLocalizedDateTime(javaFormatStyle)
        return formatter.format(zonedTime)
    }
    

    iOS:

    actual fun Instant.toDateTimeString(formatStyle: FormatStyle, timeZone: TimeZone): String {
        val nsFormatStyle = when (formatStyle) {
            FormatStyle.SHORT -> NSDateFormatterShortStyle
            FormatStyle.MEDIUM -> NSDateFormatterMediumStyle
            FormatStyle.LONG -> NSDateFormatterLongStyle
        }
        val formatter = NSDateFormatter().apply {
            dateStyle = nsFormatStyle
            timeStyle = nsFormatStyle
        }
        return formatter.stringFromDate(toNSDate())
    }
    

    JS:

    external val navigator: Navigator
    
    actual fun Instant.toDateTimeString(formatStyle: FormatStyle, timeZone: TimeZone): String {
        val locales = navigator.languages
        val date = toJSDate()
        val jsDate = Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds())
        val options = when (formatStyle) {
            FormatStyle.SHORT ->
                DateTimeFormatOptions(
                    timeZone = timeZone.id,
                    dateStyle = DateStyle.short,
                    timeStyle = TimeStyle.short,
                )
    
            FormatStyle.MEDIUM ->
                DateTimeFormatOptions(
                    timeZone = timeZone.id,
                    dateStyle = DateStyle.medium,
                    timeStyle = TimeStyle.medium,
                )
    
            FormatStyle.LONG ->
                DateTimeFormatOptions(
                    timeZone = timeZone.id,
                    dateStyle = DateStyle.long,
                    timeStyle = TimeStyle.long,
                )
        }
    
        val formatter = DateTimeFormat(locales, options)
        return formatter.format(jsDate)
    }