A multiplatform Kotlin library for working with date and time, specifically the iOS x64 target variant
—
Platform-specific extension functions and interoperability with native date/time APIs. The library provides seamless integration with Java Time API (JVM) and Foundation date/time types (Darwin/iOS/macOS).
Bidirectional conversion functions between kotlinx-datetime types and Java Time API types for seamless interoperability on the JVM platform.
/**
* Convert kotlinx.datetime.LocalDate to java.time.LocalDate
* @returns Equivalent java.time.LocalDate
*/
fun LocalDate.toJavaLocalDate(): java.time.LocalDate
/**
* Convert java.time.LocalDate to kotlinx.datetime.LocalDate
* @returns Equivalent kotlinx.datetime.LocalDate
*/
fun java.time.LocalDate.toKotlinLocalDate(): LocalDate/**
* Convert kotlinx.datetime.LocalTime to java.time.LocalTime
* @returns Equivalent java.time.LocalTime
*/
fun LocalTime.toJavaLocalTime(): java.time.LocalTime
/**
* Convert java.time.LocalTime to kotlinx.datetime.LocalTime
* @returns Equivalent kotlinx.datetime.LocalTime
*/
fun java.time.LocalTime.toKotlinLocalTime(): LocalTime/**
* Convert kotlinx.datetime.LocalDateTime to java.time.LocalDateTime
* @returns Equivalent java.time.LocalDateTime
*/
fun LocalDateTime.toJavaLocalDateTime(): java.time.LocalDateTime
/**
* Convert java.time.LocalDateTime to kotlinx.datetime.LocalDateTime
* @returns Equivalent kotlinx.datetime.LocalDateTime
*/
fun java.time.LocalDateTime.toKotlinLocalDateTime(): LocalDateTime/**
* Convert kotlinx.datetime.YearMonth to java.time.YearMonth
* @returns Equivalent java.time.YearMonth
*/
fun YearMonth.toJavaYearMonth(): java.time.YearMonth
/**
* Convert java.time.YearMonth to kotlinx.datetime.YearMonth
* @returns Equivalent kotlinx.datetime.YearMonth
*/
fun java.time.YearMonth.toKotlinYearMonth(): YearMonthUsage Examples:
import kotlinx.datetime.*
import java.time.LocalDate as JavaLocalDate
import java.time.LocalTime as JavaLocalTime
import java.time.LocalDateTime as JavaLocalDateTime
import java.time.YearMonth as JavaYearMonth
// Converting from kotlinx-datetime to Java Time
val kotlinDate = LocalDate(2023, 12, 25)
val kotlinTime = LocalTime(15, 30, 45)
val kotlinDateTime = LocalDateTime(kotlinDate, kotlinTime)
val kotlinYearMonth = YearMonth(2023, 12)
val javaDate = kotlinDate.toJavaLocalDate()
val javaTime = kotlinTime.toJavaLocalTime()
val javaDateTime = kotlinDateTime.toJavaLocalDateTime()
val javaYearMonth = kotlinYearMonth.toJavaYearMonth()
println("Java Date: $javaDate") // 2023-12-25
println("Java Time: $javaTime") // 15:30:45
println("Java DateTime: $javaDateTime") // 2023-12-25T15:30:45
println("Java YearMonth: $javaYearMonth") // 2023-12
// Converting from Java Time to kotlinx-datetime
val backToKotlinDate = javaDate.toKotlinLocalDate()
val backToKotlinTime = javaTime.toKotlinLocalTime()
val backToKotlinDateTime = javaDateTime.toKotlinLocalDateTime()
val backToKotlinYearMonth = javaYearMonth.toKotlinYearMonth()
// Verify round-trip conversion
println("Round-trip date: ${kotlinDate == backToKotlinDate}") // true
println("Round-trip time: ${kotlinTime == backToKotlinTime}") // true
println("Round-trip dateTime: ${kotlinDateTime == backToKotlinDateTime}") // true
println("Round-trip yearMonth: ${kotlinYearMonth == backToKotlinYearMonth}") // true/**
* Convert kotlinx.datetime.TimeZone to java.time.ZoneId
* @returns Equivalent java.time.ZoneId
*/
fun TimeZone.toJavaZoneId(): java.time.ZoneId
/**
* Convert java.time.ZoneId to kotlinx.datetime.TimeZone
* @returns Equivalent kotlinx.datetime.TimeZone
*/
fun java.time.ZoneId.toKotlinTimeZone(): TimeZone
/**
* Convert kotlinx.datetime.FixedOffsetTimeZone to java.time.ZoneOffset
* @returns Equivalent java.time.ZoneOffset
*/
fun FixedOffsetTimeZone.toJavaZoneOffset(): java.time.ZoneOffset
/**
* Convert java.time.ZoneOffset to kotlinx.datetime.FixedOffsetTimeZone
* @returns Equivalent kotlinx.datetime.FixedOffsetTimeZone
*/
fun java.time.ZoneOffset.toKotlinFixedOffsetTimeZone(): FixedOffsetTimeZone
/**
* Convert kotlinx.datetime.UtcOffset to java.time.ZoneOffset
* @returns Equivalent java.time.ZoneOffset
*/
fun UtcOffset.toJavaZoneOffset(): java.time.ZoneOffset
/**
* Convert java.time.ZoneOffset to kotlinx.datetime.UtcOffset
* @returns Equivalent kotlinx.datetime.UtcOffset
*/
fun java.time.ZoneOffset.toKotlinUtcOffset(): UtcOffsetUsage Examples:
import kotlinx.datetime.*
import java.time.ZoneId
import java.time.ZoneOffset
// Time zone conversions
val kotlinTimeZone = TimeZone.of("America/New_York")
val javaZoneId = kotlinTimeZone.toJavaZoneId()
val backToKotlin = javaZoneId.toKotlinTimeZone()
println("Kotlin TimeZone: ${kotlinTimeZone.id}") // America/New_York
println("Java ZoneId: $javaZoneId") // America/New_York
println("Round-trip: ${kotlinTimeZone.id == backToKotlin.id}") // true
// Offset conversions
val kotlinOffset = UtcOffset(hours = -5)
val kotlinFixedTz = FixedOffsetTimeZone(kotlinOffset)
val javaOffset = kotlinOffset.toJavaZoneOffset()
val javaOffsetFromFixed = kotlinFixedTz.toJavaZoneOffset()
println("Kotlin offset: $kotlinOffset") // -05:00
println("Java offset: $javaOffset") // -05:00
println("From fixed TZ: $javaOffsetFromFixed") // -05:00
// Convert back
val backToKotlinOffset = javaOffset.toKotlinUtcOffset()
val backToFixedTz = javaOffset.toKotlinFixedOffsetTimeZone()
println("Round-trip offset: ${kotlinOffset == backToKotlinOffset}") // true
println("Fixed TZ offset: ${backToFixedTz.offset}") // -05:00/**
* Convert kotlinx.datetime.DatePeriod to java.time.Period
* @returns Equivalent java.time.Period
*/
fun DatePeriod.toJavaPeriod(): java.time.Period
/**
* Convert java.time.Period to kotlinx.datetime.DatePeriod
* @returns Equivalent kotlinx.datetime.DatePeriod
*/
fun java.time.Period.toKotlinDatePeriod(): DatePeriodUsage Examples:
import kotlinx.datetime.*
import java.time.Period as JavaPeriod
// Period conversions
val kotlinPeriod = DatePeriod(years = 1, months = 6, days = 15)
val javaPeriod = kotlinPeriod.toJavaPeriod()
val backToKotlin = javaPeriod.toKotlinDatePeriod()
println("Kotlin period: $kotlinPeriod") // P1Y6M15D
println("Java period: $javaPeriod") // P1Y6M15D
println("Round-trip: ${kotlinPeriod == backToKotlin}") // true
// Working with Java Period arithmetic
val javaDate = JavaLocalDate.of(2023, 1, 1)
val resultDate = javaDate.plus(javaPeriod)
println("Java result: $resultDate") // 2023-07-16
// Convert result back to Kotlin
val kotlinResult = resultDate.toKotlinLocalDate()
println("Kotlin result: $kotlinResult") // 2023-07-16Conversion functions for interoperability with Foundation's date and time types on Darwin platforms (iOS, macOS, watchOS, tvOS).
/**
* Convert LocalDate to NSDateComponents
* @returns NSDateComponents with year, month, and day set
*/
fun LocalDate.toNSDateComponents(): NSDateComponents
/**
* Convert LocalDateTime to NSDateComponents
* @returns NSDateComponents with date and time components set
*/
fun LocalDateTime.toNSDateComponents(): NSDateComponents
/**
* Convert YearMonth to NSDateComponents
* @returns NSDateComponents with year and month set
*/
fun YearMonth.toNSDateComponents(): NSDateComponents/**
* Convert kotlinx.datetime.TimeZone to NSTimeZone
* @returns Equivalent NSTimeZone
*/
fun TimeZone.toNSTimeZone(): NSTimeZone
/**
* Convert NSTimeZone to kotlinx.datetime.TimeZone
* @returns Equivalent kotlinx.datetime.TimeZone
*/
fun NSTimeZone.toKotlinTimeZone(): TimeZoneUsage Examples:
// Note: This would be used in iOS/macOS code
import kotlinx.datetime.*
import platform.Foundation.*
// Convert Kotlin date/time to NSDateComponents
val kotlinDate = LocalDate(2023, 12, 25)
val kotlinDateTime = LocalDateTime(2023, 12, 25, 15, 30, 45)
val kotlinYearMonth = YearMonth(2023, 12)
val dateComponents = kotlinDate.toNSDateComponents()
val dateTimeComponents = kotlinDateTime.toNSDateComponents()
val yearMonthComponents = kotlinYearMonth.toNSDateComponents()
// Access individual components
println("Year: ${dateComponents.year}") // 2023
println("Month: ${dateComponents.month}") // 12
println("Day: ${dateComponents.day}") // 25
println("Hour: ${dateTimeComponents.hour}") // 15
println("Minute: ${dateTimeComponents.minute}") // 30
println("Second: ${dateTimeComponents.second}") // 45
// Time zone conversions
val kotlinTimeZone = TimeZone.of("America/New_York")
val nsTimeZone = kotlinTimeZone.toNSTimeZone()
val backToKotlin = nsTimeZone.toKotlinTimeZone()
println("Kotlin TZ: ${kotlinTimeZone.id}") // America/New_York
println("NS TZ: ${nsTimeZone.name}") // America/New_York
println("Round-trip: ${kotlinTimeZone.id == backToKotlin.id}") // true
// Create NSDate from components
val calendar = NSCalendar.currentCalendar
val nsDate = calendar.dateFromComponents(dateTimeComponents)
// Use with iOS/macOS APIs
val formatter = NSDateFormatter()
formatter.dateStyle = NSDateFormatterLongStyle
formatter.timeStyle = NSDateFormatterShortStyle
val formatted = formatter.stringFromDate(nsDate!!)
println("Formatted: $formatted") // "December 25, 2023 at 3:30 PM" (locale-dependent)import kotlinx.datetime.*
// Common multiplatform code
class EventScheduler {
fun createEvent(
name: String,
date: LocalDate,
time: LocalTime,
timeZone: TimeZone,
duration: DateTimePeriod
): ScheduledEvent {
val startInstant = date.atTime(time).toInstant(timeZone)
val endInstant = startInstant.plus(duration, timeZone)
return ScheduledEvent(
name = name,
start = startInstant,
end = endInstant,
timeZone = timeZone
)
}
}
data class ScheduledEvent(
val name: String,
val start: Instant,
val end: Instant,
val timeZone: TimeZone
)
// Platform-specific implementations
expect class PlatformEventIntegration {
fun addToSystemCalendar(event: ScheduledEvent)
fun showNotification(event: ScheduledEvent, beforeMinutes: Int)
}
// JVM implementation
actual class PlatformEventIntegration {
actual fun addToSystemCalendar(event: ScheduledEvent) {
// Use Java Time API for system integration
val javaStartTime = event.start.toLocalDateTime(event.timeZone).toJavaLocalDateTime()
val javaEndTime = event.end.toLocalDateTime(event.timeZone).toJavaLocalDateTime()
val javaZone = event.timeZone.toJavaZoneId()
// Integrate with Java calendar APIs
// Implementation depends on specific calendar system
}
actual fun showNotification(event: ScheduledEvent, beforeMinutes: Int) {
// Use Java notification APIs
val notificationTime = event.start.minus(beforeMinutes, DateTimeUnit.MINUTE, event.timeZone)
// Schedule notification at notificationTime
}
}
// iOS implementation
actual class PlatformEventIntegration {
actual fun addToSystemCalendar(event: ScheduledEvent) {
// Use EventKit framework
val startComponents = event.start.toLocalDateTime(event.timeZone).toNSDateComponents()
val endComponents = event.end.toLocalDateTime(event.timeZone).toNSDateComponents()
val nsTimeZone = event.timeZone.toNSTimeZone()
startComponents.timeZone = nsTimeZone
endComponents.timeZone = nsTimeZone
// Create EKEvent and add to calendar
// Implementation depends on EventKit usage
}
actual fun showNotification(event: ScheduledEvent, beforeMinutes: Int) {
// Use UserNotifications framework
val notificationTime = event.start.minus(beforeMinutes, DateTimeUnit.MINUTE, event.timeZone)
// Schedule UNNotificationRequest at notificationTime
}
}import kotlinx.datetime.*
// Common data model
@Serializable
data class Task(
val id: String,
val title: String,
val dueDate: LocalDate,
val timeZone: TimeZone,
val createdAt: Instant,
val priority: Priority
)
enum class Priority { LOW, MEDIUM, HIGH }
// Platform-specific persistence
expect class TaskRepository {
suspend fun saveTask(task: Task)
suspend fun getTasks(dateRange: LocalDateRange, timeZone: TimeZone): List<Task>
suspend fun updateTask(task: Task)
suspend fun deleteTask(id: String)
}
// JVM implementation (using SQL database)
actual class TaskRepository {
actual suspend fun saveTask(task: Task) {
// Convert to database-friendly formats
val dueDateEpochDays = task.dueDate.toEpochDays()
val createdAtEpochSeconds = task.createdAt.epochSeconds
val timeZoneId = task.timeZone.id
// SQL insert using converted values
// INSERT INTO tasks (id, title, due_date_epoch_days, timezone_id, created_at_epoch_seconds, priority)
// VALUES (?, ?, ?, ?, ?, ?)
}
actual suspend fun getTasks(dateRange: LocalDateRange, timeZone: TimeZone): List<Task> {
val startEpochDays = dateRange.start.toEpochDays()
val endEpochDays = dateRange.endInclusive.toEpochDays()
// SQL query with epoch day range
// SELECT * FROM tasks WHERE due_date_epoch_days BETWEEN ? AND ?
// Convert results back to kotlinx-datetime types
return emptyList() // Placeholder
}
actual suspend fun updateTask(task: Task) {
// Similar conversion and SQL update
}
actual suspend fun deleteTask(id: String) {
// SQL delete
}
}
// iOS implementation (using Core Data)
actual class TaskRepository {
actual suspend fun saveTask(task: Task) {
// Convert to NSDateComponents for Core Data
val dueDateComponents = task.dueDate.toNSDateComponents()
val nsTimeZone = task.timeZone.toNSTimeZone()
// Create NSManagedObject with converted values
// Set Core Data attributes using NSDateComponents
}
actual suspend fun getTasks(dateRange: LocalDateRange, timeZone: TimeZone): List<Task> {
// Convert range to NSDateComponents for Core Data predicate
val startComponents = dateRange.start.toNSDateComponents()
val endComponents = dateRange.endInclusive.toNSDateComponents()
// Create NSPredicate for date range query
// Fetch NSManagedObjects and convert back to Task instances
return emptyList() // Placeholder
}
actual suspend fun updateTask(task: Task) {
// Core Data update with NSDateComponents
}
actual suspend fun deleteTask(id: String) {
// Core Data delete
}
}import kotlinx.datetime.*
// Wrapper for legacy Java Date APIs
class LegacyDateAdapter {
// Convert from legacy java.util.Date
fun fromLegacyDate(legacyDate: java.util.Date): Instant {
// java.util.Date -> java.time.Instant -> kotlin.time.Instant
return legacyDate.toInstant().let { javaInstant ->
Instant.fromEpochSeconds(javaInstant.epochSecond, javaInstant.nano.toLong())
}
}
// Convert to legacy java.util.Date
fun toLegacyDate(instant: Instant): java.util.Date {
return java.util.Date.from(
java.time.Instant.ofEpochSecond(instant.epochSeconds, instant.nanosecondsOfSecond.toLong())
)
}
// Convert from legacy java.util.Calendar
fun fromLegacyCalendar(calendar: java.util.Calendar, timeZone: TimeZone): LocalDateTime {
val javaLocalDateTime = java.time.LocalDateTime.of(
calendar.get(java.util.Calendar.YEAR),
calendar.get(java.util.Calendar.MONTH) + 1, // Calendar months are 0-based
calendar.get(java.util.Calendar.DAY_OF_MONTH),
calendar.get(java.util.Calendar.HOUR_OF_DAY),
calendar.get(java.util.Calendar.MINUTE),
calendar.get(java.util.Calendar.SECOND),
calendar.get(java.util.Calendar.MILLISECOND) * 1_000_000
)
return javaLocalDateTime.toKotlinLocalDateTime()
}
// Convert to legacy java.util.Calendar
fun toLegacyCalendar(dateTime: LocalDateTime, timeZone: TimeZone): java.util.Calendar {
val calendar = java.util.Calendar.getInstance(timeZone.toJavaZoneId().let {
java.util.TimeZone.getTimeZone(it)
})
calendar.set(java.util.Calendar.YEAR, dateTime.year)
calendar.set(java.util.Calendar.MONTH, dateTime.monthNumber - 1) // Calendar months are 0-based
calendar.set(java.util.Calendar.DAY_OF_MONTH, dateTime.dayOfMonth)
calendar.set(java.util.Calendar.HOUR_OF_DAY, dateTime.hour)
calendar.set(java.util.Calendar.MINUTE, dateTime.minute)
calendar.set(java.util.Calendar.SECOND, dateTime.second)
calendar.set(java.util.Calendar.MILLISECOND, dateTime.nanosecond / 1_000_000)
return calendar
}
}
// Usage with legacy systems
class LegacySystemIntegration {
private val adapter = LegacyDateAdapter()
fun processLegacyData(legacyDate: java.util.Date, legacyCalendar: java.util.Calendar) {
// Convert legacy types to kotlinx-datetime
val instant = adapter.fromLegacyDate(legacyDate)
val localDateTime = adapter.fromLegacyCalendar(legacyCalendar, TimeZone.currentSystemDefault())
// Perform modern date/time operations
val tomorrow = instant.plus(1, DateTimeUnit.DAY, TimeZone.UTC)
val nextWeek = localDateTime.date.plus(1, DateTimeUnit.WEEK)
// Convert back to legacy formats if needed
val legacyTomorrow = adapter.toLegacyDate(tomorrow)
val legacyNextWeek = adapter.toLegacyCalendar(
nextWeek.atTime(localDateTime.time),
TimeZone.currentSystemDefault()
)
// Use with legacy APIs
println("Legacy tomorrow: $legacyTomorrow")
println("Legacy next week: ${legacyNextWeek.time}")
}
}import kotlinx.datetime.*
import java.time.format.DateTimeFormatter
import java.util.concurrent.ConcurrentHashMap
// Leverage Java Time performance characteristics
class OptimizedJvmDateOperations {
// Cache frequently used formatters
private val formatterCache = ConcurrentHashMap<String, DateTimeFormatter>()
fun formatWithCaching(dateTime: LocalDateTime, pattern: String): String {
val formatter = formatterCache.computeIfAbsent(pattern) {
DateTimeFormatter.ofPattern(it)
}
return dateTime.toJavaLocalDateTime().format(formatter)
}
// Bulk operations using Java streams
fun processDateRange(range: LocalDateRange, processor: (LocalDate) -> String): List<String> {
return range.asSequence()
.map { it.toJavaLocalDate() } // Convert once
.map { javaDate -> processor(javaDate.toKotlinLocalDate()) }
.toList()
}
// Efficient time zone operations
private val timeZoneCache = ConcurrentHashMap<String, java.time.ZoneId>()
fun getOptimizedTimeZone(zoneId: String): TimeZone {
val javaZone = timeZoneCache.computeIfAbsent(zoneId) {
java.time.ZoneId.of(it)
}
return javaZone.toKotlinTimeZone()
}
}// iOS-specific optimizations
class OptimizedDarwinDateOperations {
// Use NSCalendar for efficient bulk operations
fun calculateBusinessDays(start: LocalDate, end: LocalDate): Int {
val calendar = NSCalendar.currentCalendar
val startComponents = start.toNSDateComponents()
val endComponents = end.toNSDateComponents()
val startDate = calendar.dateFromComponents(startComponents)!!
val endDate = calendar.dateFromComponents(endComponents)!!
// Use NSCalendar's efficient date enumeration
var businessDays = 0
calendar.enumerateDatesStartingAfterDate(
startDate,
matchingComponents = NSDateComponents().apply { day = 1 },
options = 0u
) { date, _, stop ->
if (date != null && date <= endDate) {
val weekday = calendar.component(NSCalendarUnitWeekday, fromDate = date).toInt()
if (weekday != 1 && weekday != 7) { // Not Sunday or Saturday
businessDays++
}
} else {
stop.value = true
}
}
return businessDays
}
// Efficient time zone aware conversions
fun convertToSystemCalendar(events: List<ScheduledEvent>) {
val calendar = NSCalendar.currentCalendar
events.forEach { event ->
val components = event.start.toLocalDateTime(event.timeZone).toNSDateComponents()
components.timeZone = event.timeZone.toNSTimeZone()
// Batch calendar operations for efficiency
val systemDate = calendar.dateFromComponents(components)
// Add to system calendar in batch
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlinx--kotlinx-datetime-iosx64