CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-kotlinx--kotlinx-datetime-jvm

A multiplatform Kotlin library for working with date and time with JVM target support.

Pending
Overview
Eval results
Files

jvm-interop.mddocs/

JVM Interoperability

This document covers the bidirectional converter functions for seamless integration with existing Java codebases using java.time types. All converters provide zero-overhead conversion between kotlinx-datetime and java.time.

Overview

kotlinx-datetime provides extension functions for converting between kotlinx-datetime types and their corresponding java.time equivalents. This enables:

  • Gradual Migration: Incrementally adopt kotlinx-datetime in existing Java/Kotlin codebases
  • Library Interoperability: Use kotlinx-datetime with libraries that expect java.time types
  • Legacy Integration: Integrate with existing APIs and databases using java.time
  • Zero Overhead: Direct conversion without data loss or performance penalty

LocalDate Converters

Convert between kotlinx.datetime.LocalDate and java.time.LocalDate.

// kotlinx-datetime to java.time
fun LocalDate.toJavaLocalDate(): java.time.LocalDate

// java.time to kotlinx-datetime
fun java.time.LocalDate.toKotlinLocalDate(): LocalDate

Usage Examples

import kotlinx.datetime.LocalDate
import kotlinx.datetime.toJavaLocalDate
import kotlinx.datetime.toKotlinLocalDate

// Convert kotlinx-datetime to java.time
val kotlinxDate = LocalDate(2023, 12, 25)
val javaDate = kotlinxDate.toJavaLocalDate()

// Use with java.time APIs
val daysInMonth = javaDate.lengthOfMonth()
val isLeapYear = javaDate.isLeapYear

// Convert java.time to kotlinx-datetime
val javaDateFromDb = java.time.LocalDate.of(2023, 6, 15)
val kotlinxDate2 = javaDateFromDb.toKotlinLocalDate()

// Interoperability with existing APIs
fun processJavaDate(date: java.time.LocalDate) {
    val kotlinxDate = date.toKotlinLocalDate()
    // Use kotlinx-datetime operations
    val futureDate = kotlinxDate.plus(30, DateTimeUnit.DAY)
    println("30 days later: ${futureDate.toJavaLocalDate()}")
}

LocalTime Converters

Convert between kotlinx.datetime.LocalTime and java.time.LocalTime.

// kotlinx-datetime to java.time
fun LocalTime.toJavaLocalTime(): java.time.LocalTime

// java.time to kotlinx-datetime  
fun java.time.LocalTime.toKotlinLocalTime(): LocalTime

Usage Examples

import kotlinx.datetime.LocalTime
import kotlinx.datetime.toJavaLocalTime
import kotlinx.datetime.toKotlinLocalTime

// Convert kotlinx-datetime to java.time
val kotlinxTime = LocalTime(14, 30, 45, 123_456_789)
val javaTime = kotlinxTime.toJavaLocalTime()

// Use with java.time APIs
val hourOfDay = javaTime.hour
val truncatedToMinutes = javaTime.truncatedTo(java.time.temporal.ChronoUnit.MINUTES)

// Convert java.time to kotlinx-datetime
val javaTimeFromSystem = java.time.LocalTime.now()
val kotlinxTime2 = javaTimeFromSystem.toKotlinLocalTime()

// Database integration example
fun saveTimeToDatabase(time: LocalTime) {
    val javaTime = time.toJavaLocalTime()
    // Use with JPA/Hibernate that expects java.time.LocalTime
    entityManager.persist(TimeEntity(scheduledAt = javaTime))
}

LocalDateTime Converters

Convert between kotlinx.datetime.LocalDateTime and java.time.LocalDateTime.

// kotlinx-datetime to java.time
fun LocalDateTime.toJavaLocalDateTime(): java.time.LocalDateTime

// java.time to kotlinx-datetime
fun java.time.LocalDateTime.toKotlinLocalDateTime(): LocalDateTime

Usage Examples

import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.toJavaLocalDateTime
import kotlinx.datetime.toKotlinLocalDateTime

// Convert kotlinx-datetime to java.time
val kotlinxDateTime = LocalDateTime(2023, 12, 25, 14, 30, 45)
val javaDateTime = kotlinxDateTime.toJavaLocalDateTime()

// Use with java.time APIs
val year = javaDateTime.year
val withNano = javaDateTime.withNano(123_456_789)

// Convert java.time to kotlinx-datetime
val javaDateTimeFromApi = java.time.LocalDateTime.parse("2023-12-25T14:30:45")
val kotlinxDateTime2 = javaDateTimeFromApi.toKotlinLocalDateTime()

// API integration example
fun handleApiResponse(javaDateTime: java.time.LocalDateTime) {
    val kotlinxDateTime = javaDateTime.toKotlinLocalDateTime()
    val timeZone = TimeZone.currentSystemDefault()
    val instant = kotlinxDateTime.toInstant(timeZone)
    println("Instant: $instant")
}

Instant Converters

Convert between kotlin.time.Instant and java.time.Instant.

// kotlin.time to java.time
fun Instant.toJavaInstant(): java.time.Instant

// java.time to kotlin.time
fun java.time.Instant.toKotlinInstant(): Instant

Usage Examples

import kotlin.time.Instant
import kotlinx.datetime.toJavaInstant
import kotlinx.datetime.toKotlinInstant
import kotlinx.datetime.Clock

// Convert kotlin.time to java.time
val kotlinInstant = Clock.System.now()
val javaInstant = kotlinInstant.toJavaInstant()

// Use with java.time APIs
val epochMilli = javaInstant.toEpochMilli()
val plusSeconds = javaInstant.plusSeconds(3600)

// Convert java.time to kotlin.time
val javaInstantFromSystem = java.time.Instant.now()
val kotlinInstant2 = javaInstantFromSystem.toKotlinInstant()

// Database timestamp example
fun logEvent(event: String) {
    val instant = Clock.System.now()
    val javaInstant = instant.toJavaInstant()
    // Use with database APIs expecting java.time.Instant
    val timestamp = java.sql.Timestamp.from(javaInstant)
    logRepository.save(LogEntry(event, timestamp))
}

TimeZone Converters

Convert between kotlinx.datetime.TimeZone and java.time.ZoneId.

// kotlinx-datetime to java.time
fun TimeZone.toJavaZoneId(): java.time.ZoneId

// java.time to kotlinx-datetime
fun java.time.ZoneId.toKotlinTimeZone(): TimeZone

Usage Examples

import kotlinx.datetime.TimeZone
import kotlinx.datetime.toJavaZoneId
import kotlinx.datetime.toKotlinTimeZone

// Convert kotlinx-datetime to java.time
val kotlinxTimeZone = TimeZone.of("America/New_York")
val javaZoneId = kotlinxTimeZone.toJavaZoneId()

// Use with java.time APIs
val zoneRules = javaZoneId.rules
val displayName = javaZoneId.getDisplayName(
    java.time.format.TextStyle.FULL,
    java.util.Locale.US
)

// Convert java.time to kotlinx-datetime
val javaZoneFromSystem = java.time.ZoneId.systemDefault()
val kotlinxTimeZone2 = javaZoneFromSystem.toKotlinTimeZone()

// Scheduling system integration
fun scheduleTask(dateTime: LocalDateTime, timeZone: TimeZone) {
    val javaDateTime = dateTime.toJavaLocalDateTime()
    val javaZone = timeZone.toJavaZoneId()
    val zonedDateTime = java.time.ZonedDateTime.of(javaDateTime, javaZone)
    
    // Use with scheduling library expecting java.time types
    scheduler.schedule(task, zonedDateTime)
}

UtcOffset Converters

Convert between kotlinx.datetime.UtcOffset and java.time.ZoneOffset.

// kotlinx-datetime to java.time
fun UtcOffset.toJavaZoneOffset(): java.time.ZoneOffset

// java.time to kotlinx-datetime
fun java.time.ZoneOffset.toKotlinUtcOffset(): UtcOffset

Usage Examples

import kotlinx.datetime.UtcOffset
import kotlinx.datetime.toJavaZoneOffset
import kotlinx.datetime.toKotlinUtcOffset

// Convert kotlinx-datetime to java.time
val kotlinxOffset = UtcOffset(hours = -5, minutes = 30)
val javaOffset = kotlinxOffset.toJavaZoneOffset()

// Use with java.time APIs
val totalSeconds = javaOffset.totalSeconds
val offsetTime = java.time.OffsetTime.of(14, 30, 0, 0, javaOffset)

// Convert java.time to kotlinx-datetime
val javaOffsetFromApi = java.time.ZoneOffset.ofHours(2)
val kotlinxOffset2 = javaOffsetFromApi.toKotlinUtcOffset()

Month Converters

Convert between kotlinx.datetime.Month and java.time.Month.

// kotlinx-datetime to java.time
fun Month.toJavaMonth(): java.time.Month

// java.time to kotlinx-datetime
fun java.time.Month.toKotlinMonth(): Month

Usage Examples

import kotlinx.datetime.Month
import kotlinx.datetime.toJavaMonth
import kotlinx.datetime.toKotlinMonth

// Convert kotlinx-datetime to java.time
val kotlinxMonth = Month.DECEMBER
val javaMonth = kotlinxMonth.toJavaMonth()

// Use with java.time APIs
val monthValue = javaMonth.value // 12
val displayName = javaMonth.getDisplayName(
    java.time.format.TextStyle.FULL,
    java.util.Locale.US
) // "December"

// Convert java.time to kotlinx-datetime
val javaMonthFromApi = java.time.Month.JUNE
val kotlinxMonth2 = javaMonthFromApi.toKotlinMonth()

// Business logic example
fun getSeasonForMonth(month: Month): String {
    val javaMonth = month.toJavaMonth()
    return when (javaMonth) {
        java.time.Month.DECEMBER, java.time.Month.JANUARY, java.time.Month.FEBRUARY -> "Winter"
        java.time.Month.MARCH, java.time.Month.APRIL, java.time.Month.MAY -> "Spring"
        java.time.Month.JUNE, java.time.Month.JULY, java.time.Month.AUGUST -> "Summer"
        else -> "Fall"
    }
}

YearMonth Converters

Convert between kotlinx.datetime.YearMonth and java.time.YearMonth.

// kotlinx-datetime to java.time
fun YearMonth.toJavaYearMonth(): java.time.YearMonth

// java.time to kotlinx-datetime
fun java.time.YearMonth.toKotlinYearMonth(): YearMonth

Usage Examples

import kotlinx.datetime.YearMonth
import kotlinx.datetime.toJavaYearMonth
import kotlinx.datetime.toKotlinYearMonth

// Convert kotlinx-datetime to java.time
val kotlinxYearMonth = YearMonth(2023, 12)
val javaYearMonth = kotlinxYearMonth.toJavaYearMonth()

// Use with java.time APIs
val lengthOfMonth = javaYearMonth.lengthOfMonth() // 31
val isLeapYear = javaYearMonth.isLeapYear

// Convert java.time to kotlinx-datetime
val javaYearMonthFromDb = java.time.YearMonth.of(2023, 6)
val kotlinxYearMonth2 = javaYearMonthFromDb.toKotlinYearMonth()

// Reporting system example
fun generateMonthlyReport(yearMonth: YearMonth): Report {
    val javaYearMonth = yearMonth.toJavaYearMonth()
    val startOfMonth = javaYearMonth.atDay(1)
    val endOfMonth = javaYearMonth.atEndOfMonth()
    
    return Report(
        period = yearMonth,
        startDate = startOfMonth.toKotlinLocalDate(),
        endDate = endOfMonth.toKotlinLocalDate()
    )
}

DayOfWeek Converters

Convert between kotlinx.datetime.DayOfWeek and java.time.DayOfWeek.

// kotlinx-datetime to java.time
fun DayOfWeek.toJavaDayOfWeek(): java.time.DayOfWeek

// java.time to kotlinx-datetime
fun java.time.DayOfWeek.toKotlinDayOfWeek(): DayOfWeek

Usage Examples

import kotlinx.datetime.DayOfWeek
import kotlinx.datetime.toJavaDayOfWeek
import kotlinx.datetime.toKotlinDayOfWeek

// Convert kotlinx-datetime to java.time
val kotlinxDayOfWeek = DayOfWeek.FRIDAY
val javaDayOfWeek = kotlinxDayOfWeek.toJavaDayOfWeek()

// Use with java.time APIs
val dayValue = javaDayOfWeek.value // 5
val displayName = javaDayOfWeek.getDisplayName(
    java.time.format.TextStyle.FULL,
    java.util.Locale.US
) // "Friday"

// Convert java.time to kotlinx-datetime
val javaDayFromTemporal = java.time.LocalDate.now().dayOfWeek
val kotlinxDayOfWeek2 = javaDayFromTemporal.toKotlinDayOfWeek()

// Business hours calculation example
fun isBusinessDay(dayOfWeek: DayOfWeek): Boolean {
    val javaDayOfWeek = dayOfWeek.toJavaDayOfWeek()
    return javaDayOfWeek != java.time.DayOfWeek.SATURDAY && 
           javaDayOfWeek != java.time.DayOfWeek.SUNDAY
}

Duration Converters

Convert between kotlin.time.Duration and java.time.Duration.

// kotlin.time to java.time
fun Duration.toJavaDuration(): java.time.Duration

// java.time to kotlin.time
fun java.time.Duration.toKotlinDuration(): Duration

Usage Examples

import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes
import kotlinx.datetime.toJavaDuration
import kotlinx.datetime.toKotlinDuration

// Convert kotlin.time to java.time
val kotlinDuration = 2.hours + 30.minutes
val javaDuration = kotlinDuration.toJavaDuration()

// Use with java.time APIs
val seconds = javaDuration.seconds
val nanos = javaDuration.nano

// Convert java.time to kotlin.time
val javaDurationFromApi = java.time.Duration.ofHours(8)
val kotlinDuration2 = javaDurationFromApi.toKotlinDuration()

// Task scheduling example
fun schedulePeriodicTask(interval: Duration) {
    val javaDuration = interval.toJavaDuration()
    // Use with Java scheduling APIs
    scheduledExecutor.scheduleAtFixedRate(
        task,
        0,
        javaDuration.toMillis(),
        java.util.concurrent.TimeUnit.MILLISECONDS
    )
}

Common Integration Patterns

Database Integration

// JPA Entity with java.time types
@Entity
data class EventEntity(
    @Id val id: String,
    val title: String,
    val startTime: java.time.Instant,
    val date: java.time.LocalDate,
    val timeZone: String
)

// Service layer with kotlinx-datetime
class EventService {
    fun createEvent(title: String, dateTime: LocalDateTime, timeZone: TimeZone): String {
        val instant = dateTime.toInstant(timeZone)
        val entity = EventEntity(
            id = UUID.randomUUID().toString(),
            title = title,
            startTime = instant.toJavaInstant(),    // Convert for database
            date = dateTime.date.toJavaLocalDate(), // Convert for database
            timeZone = timeZone.id
        )
        return repository.save(entity).id
    }
    
    fun getEvent(id: String): Event? {
        val entity = repository.findById(id) ?: return null
        return Event(
            id = entity.id,
            title = entity.title,
            instant = entity.startTime.toKotlinInstant(),        // Convert from database
            date = entity.date.toKotlinLocalDate(),              // Convert from database
            timeZone = TimeZone.of(entity.timeZone)
        )
    }
}

API Integration

// External API client expecting java.time types
class ExternalCalendarClient {
    fun scheduleEvent(
        title: String,
        startTime: java.time.ZonedDateTime,
        duration: java.time.Duration
    ): CompletableFuture<String>
}

// Internal service using kotlinx-datetime
class CalendarService(private val client: ExternalCalendarClient) {
    suspend fun scheduleEvent(
        title: String,
        dateTime: LocalDateTime,
        timeZone: TimeZone,
        duration: DateTimePeriod
    ): String {
        // Convert kotlinx-datetime types to java.time for external API
        val javaDateTime = dateTime.toJavaLocalDateTime()
        val javaZoneId = timeZone.toJavaZoneId()
        val zonedDateTime = java.time.ZonedDateTime.of(javaDateTime, javaZoneId)
        
        // Convert period to duration (simplified for time-based components)
        val javaDuration = java.time.Duration.ofHours(duration.hours.toLong())
            .plusMinutes(duration.minutes.toLong())
            .plusSeconds(duration.seconds.toLong())
        
        return client.scheduleEvent(title, zonedDateTime, javaDuration).await()
    }
}

Legacy Code Migration

// Legacy code using java.time
class LegacyDateUtils {
    companion object {
        @JvmStatic
        fun addBusinessDays(date: java.time.LocalDate, days: Int): java.time.LocalDate {
            // Existing java.time-based logic
            var result = date
            var addedDays = 0
            while (addedDays < days) {
                result = result.plusDays(1)
                if (result.dayOfWeek != java.time.DayOfWeek.SATURDAY && 
                    result.dayOfWeek != java.time.DayOfWeek.SUNDAY) {
                    addedDays++
                }
            }
            return result
        }
    }
}

// New code using kotlinx-datetime with legacy integration
class ModernDateService {
    fun addBusinessDays(date: LocalDate, days: Int): LocalDate {
        val javaDate = date.toJavaLocalDate()
        val resultJavaDate = LegacyDateUtils.addBusinessDays(javaDate, days)
        return resultJavaDate.toKotlinLocalDate()
    }
}

Performance Considerations

  • Zero Overhead: All conversions are direct mappings with no additional allocations
  • Nullable Handling: java.time types are non-nullable, kotlinx-datetime types are also non-nullable
  • Precision: All conversions preserve full precision (nanoseconds for time, exact values for dates)
  • Timezone Data: Both libraries use the same underlying timezone database, ensuring consistency
  • Memory: No additional memory overhead beyond the objects themselves

Best Practices

  1. Conversion Boundaries: Convert at system boundaries (database, API, legacy code)
  2. Internal Consistency: Use one datetime library consistently within modules
  3. Gradual Migration: Convert incrementally, starting with new code
  4. Testing: Test conversion roundtrips to ensure data integrity
  5. Documentation: Document which library is used in which parts of the codebase

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-kotlinx--kotlinx-datetime-jvm

docs

core-types.md

formatting.md

index.md

jvm-interop.md

periods-units.md

serialization.md

tile.json