0
# JVM Interoperability
1
2
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.
3
4
## Overview
5
6
kotlinx-datetime provides extension functions for converting between kotlinx-datetime types and their corresponding `java.time` equivalents. This enables:
7
8
- **Gradual Migration**: Incrementally adopt kotlinx-datetime in existing Java/Kotlin codebases
9
- **Library Interoperability**: Use kotlinx-datetime with libraries that expect java.time types
10
- **Legacy Integration**: Integrate with existing APIs and databases using java.time
11
- **Zero Overhead**: Direct conversion without data loss or performance penalty
12
13
## LocalDate Converters
14
15
Convert between `kotlinx.datetime.LocalDate` and `java.time.LocalDate`.
16
17
```kotlin { .api }
18
// kotlinx-datetime to java.time
19
fun LocalDate.toJavaLocalDate(): java.time.LocalDate
20
21
// java.time to kotlinx-datetime
22
fun java.time.LocalDate.toKotlinLocalDate(): LocalDate
23
```
24
25
### Usage Examples
26
27
```kotlin
28
import kotlinx.datetime.LocalDate
29
import kotlinx.datetime.toJavaLocalDate
30
import kotlinx.datetime.toKotlinLocalDate
31
32
// Convert kotlinx-datetime to java.time
33
val kotlinxDate = LocalDate(2023, 12, 25)
34
val javaDate = kotlinxDate.toJavaLocalDate()
35
36
// Use with java.time APIs
37
val daysInMonth = javaDate.lengthOfMonth()
38
val isLeapYear = javaDate.isLeapYear
39
40
// Convert java.time to kotlinx-datetime
41
val javaDateFromDb = java.time.LocalDate.of(2023, 6, 15)
42
val kotlinxDate2 = javaDateFromDb.toKotlinLocalDate()
43
44
// Interoperability with existing APIs
45
fun processJavaDate(date: java.time.LocalDate) {
46
val kotlinxDate = date.toKotlinLocalDate()
47
// Use kotlinx-datetime operations
48
val futureDate = kotlinxDate.plus(30, DateTimeUnit.DAY)
49
println("30 days later: ${futureDate.toJavaLocalDate()}")
50
}
51
```
52
53
## LocalTime Converters
54
55
Convert between `kotlinx.datetime.LocalTime` and `java.time.LocalTime`.
56
57
```kotlin { .api }
58
// kotlinx-datetime to java.time
59
fun LocalTime.toJavaLocalTime(): java.time.LocalTime
60
61
// java.time to kotlinx-datetime
62
fun java.time.LocalTime.toKotlinLocalTime(): LocalTime
63
```
64
65
### Usage Examples
66
67
```kotlin
68
import kotlinx.datetime.LocalTime
69
import kotlinx.datetime.toJavaLocalTime
70
import kotlinx.datetime.toKotlinLocalTime
71
72
// Convert kotlinx-datetime to java.time
73
val kotlinxTime = LocalTime(14, 30, 45, 123_456_789)
74
val javaTime = kotlinxTime.toJavaLocalTime()
75
76
// Use with java.time APIs
77
val hourOfDay = javaTime.hour
78
val truncatedToMinutes = javaTime.truncatedTo(java.time.temporal.ChronoUnit.MINUTES)
79
80
// Convert java.time to kotlinx-datetime
81
val javaTimeFromSystem = java.time.LocalTime.now()
82
val kotlinxTime2 = javaTimeFromSystem.toKotlinLocalTime()
83
84
// Database integration example
85
fun saveTimeToDatabase(time: LocalTime) {
86
val javaTime = time.toJavaLocalTime()
87
// Use with JPA/Hibernate that expects java.time.LocalTime
88
entityManager.persist(TimeEntity(scheduledAt = javaTime))
89
}
90
```
91
92
## LocalDateTime Converters
93
94
Convert between `kotlinx.datetime.LocalDateTime` and `java.time.LocalDateTime`.
95
96
```kotlin { .api }
97
// kotlinx-datetime to java.time
98
fun LocalDateTime.toJavaLocalDateTime(): java.time.LocalDateTime
99
100
// java.time to kotlinx-datetime
101
fun java.time.LocalDateTime.toKotlinLocalDateTime(): LocalDateTime
102
```
103
104
### Usage Examples
105
106
```kotlin
107
import kotlinx.datetime.LocalDateTime
108
import kotlinx.datetime.toJavaLocalDateTime
109
import kotlinx.datetime.toKotlinLocalDateTime
110
111
// Convert kotlinx-datetime to java.time
112
val kotlinxDateTime = LocalDateTime(2023, 12, 25, 14, 30, 45)
113
val javaDateTime = kotlinxDateTime.toJavaLocalDateTime()
114
115
// Use with java.time APIs
116
val year = javaDateTime.year
117
val withNano = javaDateTime.withNano(123_456_789)
118
119
// Convert java.time to kotlinx-datetime
120
val javaDateTimeFromApi = java.time.LocalDateTime.parse("2023-12-25T14:30:45")
121
val kotlinxDateTime2 = javaDateTimeFromApi.toKotlinLocalDateTime()
122
123
// API integration example
124
fun handleApiResponse(javaDateTime: java.time.LocalDateTime) {
125
val kotlinxDateTime = javaDateTime.toKotlinLocalDateTime()
126
val timeZone = TimeZone.currentSystemDefault()
127
val instant = kotlinxDateTime.toInstant(timeZone)
128
println("Instant: $instant")
129
}
130
```
131
132
## Instant Converters
133
134
Convert between `kotlin.time.Instant` and `java.time.Instant`.
135
136
```kotlin { .api }
137
// kotlin.time to java.time
138
fun Instant.toJavaInstant(): java.time.Instant
139
140
// java.time to kotlin.time
141
fun java.time.Instant.toKotlinInstant(): Instant
142
```
143
144
### Usage Examples
145
146
```kotlin
147
import kotlin.time.Instant
148
import kotlinx.datetime.toJavaInstant
149
import kotlinx.datetime.toKotlinInstant
150
import kotlinx.datetime.Clock
151
152
// Convert kotlin.time to java.time
153
val kotlinInstant = Clock.System.now()
154
val javaInstant = kotlinInstant.toJavaInstant()
155
156
// Use with java.time APIs
157
val epochMilli = javaInstant.toEpochMilli()
158
val plusSeconds = javaInstant.plusSeconds(3600)
159
160
// Convert java.time to kotlin.time
161
val javaInstantFromSystem = java.time.Instant.now()
162
val kotlinInstant2 = javaInstantFromSystem.toKotlinInstant()
163
164
// Database timestamp example
165
fun logEvent(event: String) {
166
val instant = Clock.System.now()
167
val javaInstant = instant.toJavaInstant()
168
// Use with database APIs expecting java.time.Instant
169
val timestamp = java.sql.Timestamp.from(javaInstant)
170
logRepository.save(LogEntry(event, timestamp))
171
}
172
```
173
174
## TimeZone Converters
175
176
Convert between `kotlinx.datetime.TimeZone` and `java.time.ZoneId`.
177
178
```kotlin { .api }
179
// kotlinx-datetime to java.time
180
fun TimeZone.toJavaZoneId(): java.time.ZoneId
181
182
// java.time to kotlinx-datetime
183
fun java.time.ZoneId.toKotlinTimeZone(): TimeZone
184
```
185
186
### Usage Examples
187
188
```kotlin
189
import kotlinx.datetime.TimeZone
190
import kotlinx.datetime.toJavaZoneId
191
import kotlinx.datetime.toKotlinTimeZone
192
193
// Convert kotlinx-datetime to java.time
194
val kotlinxTimeZone = TimeZone.of("America/New_York")
195
val javaZoneId = kotlinxTimeZone.toJavaZoneId()
196
197
// Use with java.time APIs
198
val zoneRules = javaZoneId.rules
199
val displayName = javaZoneId.getDisplayName(
200
java.time.format.TextStyle.FULL,
201
java.util.Locale.US
202
)
203
204
// Convert java.time to kotlinx-datetime
205
val javaZoneFromSystem = java.time.ZoneId.systemDefault()
206
val kotlinxTimeZone2 = javaZoneFromSystem.toKotlinTimeZone()
207
208
// Scheduling system integration
209
fun scheduleTask(dateTime: LocalDateTime, timeZone: TimeZone) {
210
val javaDateTime = dateTime.toJavaLocalDateTime()
211
val javaZone = timeZone.toJavaZoneId()
212
val zonedDateTime = java.time.ZonedDateTime.of(javaDateTime, javaZone)
213
214
// Use with scheduling library expecting java.time types
215
scheduler.schedule(task, zonedDateTime)
216
}
217
```
218
219
## UtcOffset Converters
220
221
Convert between `kotlinx.datetime.UtcOffset` and `java.time.ZoneOffset`.
222
223
```kotlin { .api }
224
// kotlinx-datetime to java.time
225
fun UtcOffset.toJavaZoneOffset(): java.time.ZoneOffset
226
227
// java.time to kotlinx-datetime
228
fun java.time.ZoneOffset.toKotlinUtcOffset(): UtcOffset
229
```
230
231
### Usage Examples
232
233
```kotlin
234
import kotlinx.datetime.UtcOffset
235
import kotlinx.datetime.toJavaZoneOffset
236
import kotlinx.datetime.toKotlinUtcOffset
237
238
// Convert kotlinx-datetime to java.time
239
val kotlinxOffset = UtcOffset(hours = -5, minutes = 30)
240
val javaOffset = kotlinxOffset.toJavaZoneOffset()
241
242
// Use with java.time APIs
243
val totalSeconds = javaOffset.totalSeconds
244
val offsetTime = java.time.OffsetTime.of(14, 30, 0, 0, javaOffset)
245
246
// Convert java.time to kotlinx-datetime
247
val javaOffsetFromApi = java.time.ZoneOffset.ofHours(2)
248
val kotlinxOffset2 = javaOffsetFromApi.toKotlinUtcOffset()
249
```
250
251
## Month Converters
252
253
Convert between `kotlinx.datetime.Month` and `java.time.Month`.
254
255
```kotlin { .api }
256
// kotlinx-datetime to java.time
257
fun Month.toJavaMonth(): java.time.Month
258
259
// java.time to kotlinx-datetime
260
fun java.time.Month.toKotlinMonth(): Month
261
```
262
263
### Usage Examples
264
265
```kotlin
266
import kotlinx.datetime.Month
267
import kotlinx.datetime.toJavaMonth
268
import kotlinx.datetime.toKotlinMonth
269
270
// Convert kotlinx-datetime to java.time
271
val kotlinxMonth = Month.DECEMBER
272
val javaMonth = kotlinxMonth.toJavaMonth()
273
274
// Use with java.time APIs
275
val monthValue = javaMonth.value // 12
276
val displayName = javaMonth.getDisplayName(
277
java.time.format.TextStyle.FULL,
278
java.util.Locale.US
279
) // "December"
280
281
// Convert java.time to kotlinx-datetime
282
val javaMonthFromApi = java.time.Month.JUNE
283
val kotlinxMonth2 = javaMonthFromApi.toKotlinMonth()
284
285
// Business logic example
286
fun getSeasonForMonth(month: Month): String {
287
val javaMonth = month.toJavaMonth()
288
return when (javaMonth) {
289
java.time.Month.DECEMBER, java.time.Month.JANUARY, java.time.Month.FEBRUARY -> "Winter"
290
java.time.Month.MARCH, java.time.Month.APRIL, java.time.Month.MAY -> "Spring"
291
java.time.Month.JUNE, java.time.Month.JULY, java.time.Month.AUGUST -> "Summer"
292
else -> "Fall"
293
}
294
}
295
```
296
297
## YearMonth Converters
298
299
Convert between `kotlinx.datetime.YearMonth` and `java.time.YearMonth`.
300
301
```kotlin { .api }
302
// kotlinx-datetime to java.time
303
fun YearMonth.toJavaYearMonth(): java.time.YearMonth
304
305
// java.time to kotlinx-datetime
306
fun java.time.YearMonth.toKotlinYearMonth(): YearMonth
307
```
308
309
### Usage Examples
310
311
```kotlin
312
import kotlinx.datetime.YearMonth
313
import kotlinx.datetime.toJavaYearMonth
314
import kotlinx.datetime.toKotlinYearMonth
315
316
// Convert kotlinx-datetime to java.time
317
val kotlinxYearMonth = YearMonth(2023, 12)
318
val javaYearMonth = kotlinxYearMonth.toJavaYearMonth()
319
320
// Use with java.time APIs
321
val lengthOfMonth = javaYearMonth.lengthOfMonth() // 31
322
val isLeapYear = javaYearMonth.isLeapYear
323
324
// Convert java.time to kotlinx-datetime
325
val javaYearMonthFromDb = java.time.YearMonth.of(2023, 6)
326
val kotlinxYearMonth2 = javaYearMonthFromDb.toKotlinYearMonth()
327
328
// Reporting system example
329
fun generateMonthlyReport(yearMonth: YearMonth): Report {
330
val javaYearMonth = yearMonth.toJavaYearMonth()
331
val startOfMonth = javaYearMonth.atDay(1)
332
val endOfMonth = javaYearMonth.atEndOfMonth()
333
334
return Report(
335
period = yearMonth,
336
startDate = startOfMonth.toKotlinLocalDate(),
337
endDate = endOfMonth.toKotlinLocalDate()
338
)
339
}
340
```
341
342
## DayOfWeek Converters
343
344
Convert between `kotlinx.datetime.DayOfWeek` and `java.time.DayOfWeek`.
345
346
```kotlin { .api }
347
// kotlinx-datetime to java.time
348
fun DayOfWeek.toJavaDayOfWeek(): java.time.DayOfWeek
349
350
// java.time to kotlinx-datetime
351
fun java.time.DayOfWeek.toKotlinDayOfWeek(): DayOfWeek
352
```
353
354
### Usage Examples
355
356
```kotlin
357
import kotlinx.datetime.DayOfWeek
358
import kotlinx.datetime.toJavaDayOfWeek
359
import kotlinx.datetime.toKotlinDayOfWeek
360
361
// Convert kotlinx-datetime to java.time
362
val kotlinxDayOfWeek = DayOfWeek.FRIDAY
363
val javaDayOfWeek = kotlinxDayOfWeek.toJavaDayOfWeek()
364
365
// Use with java.time APIs
366
val dayValue = javaDayOfWeek.value // 5
367
val displayName = javaDayOfWeek.getDisplayName(
368
java.time.format.TextStyle.FULL,
369
java.util.Locale.US
370
) // "Friday"
371
372
// Convert java.time to kotlinx-datetime
373
val javaDayFromTemporal = java.time.LocalDate.now().dayOfWeek
374
val kotlinxDayOfWeek2 = javaDayFromTemporal.toKotlinDayOfWeek()
375
376
// Business hours calculation example
377
fun isBusinessDay(dayOfWeek: DayOfWeek): Boolean {
378
val javaDayOfWeek = dayOfWeek.toJavaDayOfWeek()
379
return javaDayOfWeek != java.time.DayOfWeek.SATURDAY &&
380
javaDayOfWeek != java.time.DayOfWeek.SUNDAY
381
}
382
```
383
384
## Duration Converters
385
386
Convert between `kotlin.time.Duration` and `java.time.Duration`.
387
388
```kotlin { .api }
389
// kotlin.time to java.time
390
fun Duration.toJavaDuration(): java.time.Duration
391
392
// java.time to kotlin.time
393
fun java.time.Duration.toKotlinDuration(): Duration
394
```
395
396
### Usage Examples
397
398
```kotlin
399
import kotlin.time.Duration
400
import kotlin.time.Duration.Companion.hours
401
import kotlin.time.Duration.Companion.minutes
402
import kotlinx.datetime.toJavaDuration
403
import kotlinx.datetime.toKotlinDuration
404
405
// Convert kotlin.time to java.time
406
val kotlinDuration = 2.hours + 30.minutes
407
val javaDuration = kotlinDuration.toJavaDuration()
408
409
// Use with java.time APIs
410
val seconds = javaDuration.seconds
411
val nanos = javaDuration.nano
412
413
// Convert java.time to kotlin.time
414
val javaDurationFromApi = java.time.Duration.ofHours(8)
415
val kotlinDuration2 = javaDurationFromApi.toKotlinDuration()
416
417
// Task scheduling example
418
fun schedulePeriodicTask(interval: Duration) {
419
val javaDuration = interval.toJavaDuration()
420
// Use with Java scheduling APIs
421
scheduledExecutor.scheduleAtFixedRate(
422
task,
423
0,
424
javaDuration.toMillis(),
425
java.util.concurrent.TimeUnit.MILLISECONDS
426
)
427
}
428
```
429
430
## Common Integration Patterns
431
432
### Database Integration
433
434
```kotlin
435
// JPA Entity with java.time types
436
@Entity
437
data class EventEntity(
438
@Id val id: String,
439
val title: String,
440
val startTime: java.time.Instant,
441
val date: java.time.LocalDate,
442
val timeZone: String
443
)
444
445
// Service layer with kotlinx-datetime
446
class EventService {
447
fun createEvent(title: String, dateTime: LocalDateTime, timeZone: TimeZone): String {
448
val instant = dateTime.toInstant(timeZone)
449
val entity = EventEntity(
450
id = UUID.randomUUID().toString(),
451
title = title,
452
startTime = instant.toJavaInstant(), // Convert for database
453
date = dateTime.date.toJavaLocalDate(), // Convert for database
454
timeZone = timeZone.id
455
)
456
return repository.save(entity).id
457
}
458
459
fun getEvent(id: String): Event? {
460
val entity = repository.findById(id) ?: return null
461
return Event(
462
id = entity.id,
463
title = entity.title,
464
instant = entity.startTime.toKotlinInstant(), // Convert from database
465
date = entity.date.toKotlinLocalDate(), // Convert from database
466
timeZone = TimeZone.of(entity.timeZone)
467
)
468
}
469
}
470
```
471
472
### API Integration
473
474
```kotlin
475
// External API client expecting java.time types
476
class ExternalCalendarClient {
477
fun scheduleEvent(
478
title: String,
479
startTime: java.time.ZonedDateTime,
480
duration: java.time.Duration
481
): CompletableFuture<String>
482
}
483
484
// Internal service using kotlinx-datetime
485
class CalendarService(private val client: ExternalCalendarClient) {
486
suspend fun scheduleEvent(
487
title: String,
488
dateTime: LocalDateTime,
489
timeZone: TimeZone,
490
duration: DateTimePeriod
491
): String {
492
// Convert kotlinx-datetime types to java.time for external API
493
val javaDateTime = dateTime.toJavaLocalDateTime()
494
val javaZoneId = timeZone.toJavaZoneId()
495
val zonedDateTime = java.time.ZonedDateTime.of(javaDateTime, javaZoneId)
496
497
// Convert period to duration (simplified for time-based components)
498
val javaDuration = java.time.Duration.ofHours(duration.hours.toLong())
499
.plusMinutes(duration.minutes.toLong())
500
.plusSeconds(duration.seconds.toLong())
501
502
return client.scheduleEvent(title, zonedDateTime, javaDuration).await()
503
}
504
}
505
```
506
507
### Legacy Code Migration
508
509
```kotlin
510
// Legacy code using java.time
511
class LegacyDateUtils {
512
companion object {
513
@JvmStatic
514
fun addBusinessDays(date: java.time.LocalDate, days: Int): java.time.LocalDate {
515
// Existing java.time-based logic
516
var result = date
517
var addedDays = 0
518
while (addedDays < days) {
519
result = result.plusDays(1)
520
if (result.dayOfWeek != java.time.DayOfWeek.SATURDAY &&
521
result.dayOfWeek != java.time.DayOfWeek.SUNDAY) {
522
addedDays++
523
}
524
}
525
return result
526
}
527
}
528
}
529
530
// New code using kotlinx-datetime with legacy integration
531
class ModernDateService {
532
fun addBusinessDays(date: LocalDate, days: Int): LocalDate {
533
val javaDate = date.toJavaLocalDate()
534
val resultJavaDate = LegacyDateUtils.addBusinessDays(javaDate, days)
535
return resultJavaDate.toKotlinLocalDate()
536
}
537
}
538
```
539
540
## Performance Considerations
541
542
- **Zero Overhead**: All conversions are direct mappings with no additional allocations
543
- **Nullable Handling**: java.time types are non-nullable, kotlinx-datetime types are also non-nullable
544
- **Precision**: All conversions preserve full precision (nanoseconds for time, exact values for dates)
545
- **Timezone Data**: Both libraries use the same underlying timezone database, ensuring consistency
546
- **Memory**: No additional memory overhead beyond the objects themselves
547
548
## Best Practices
549
550
1. **Conversion Boundaries**: Convert at system boundaries (database, API, legacy code)
551
2. **Internal Consistency**: Use one datetime library consistently within modules
552
3. **Gradual Migration**: Convert incrementally, starting with new code
553
4. **Testing**: Test conversion roundtrips to ensure data integrity
554
5. **Documentation**: Document which library is used in which parts of the codebase