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

serialization.mddocs/

Serialization Support

This document covers the complete serialization support for all datetime types, including ISO 8601 string serializers, component-based JSON object serializers, and custom format serializers.

Overview

kotlinx-datetime provides comprehensive serialization support through kotlinx.serialization, offering multiple serialization strategies:

  • ISO 8601 Serializers: Serialize as standardized ISO strings
  • Component Serializers: Serialize as JSON objects with separate fields
  • Custom Format Serializers: Use custom format patterns for serialization

ISO 8601 String Serializers

These serializers represent datetime values as ISO 8601 standard strings.

InstantIso8601Serializer

object InstantIso8601Serializer : KSerializer<Instant>

Serializes Instant as ISO 8601 string with UTC timezone.

@Serializable
data class Event(
    @Serializable(with = InstantIso8601Serializer::class)
    val timestamp: Instant
)

// JSON: {"timestamp": "2023-12-25T14:30:00Z"}

LocalDateIso8601Serializer

object LocalDateIso8601Serializer : KSerializer<LocalDate>

Serializes LocalDate as ISO 8601 date string.

@Serializable
data class Person(
    @Serializable(with = LocalDateIso8601Serializer::class)
    val birthDate: LocalDate
)

// JSON: {"birthDate": "1990-06-15"}

LocalTimeIso8601Serializer

object LocalTimeIso8601Serializer : KSerializer<LocalTime>

Serializes LocalTime as ISO 8601 time string.

@Serializable  
data class Schedule(
    @Serializable(with = LocalTimeIso8601Serializer::class)
    val startTime: LocalTime
)

// JSON: {"startTime": "09:30:00"}

LocalDateTimeIso8601Serializer

object LocalDateTimeIso8601Serializer : KSerializer<LocalDateTime>

Serializes LocalDateTime as ISO 8601 datetime string.

@Serializable
data class Appointment(
    @Serializable(with = LocalDateTimeIso8601Serializer::class)
    val scheduledAt: LocalDateTime
)

// JSON: {"scheduledAt": "2023-12-25T14:30:00"}

TimeZoneSerializer

object TimeZoneSerializer : KSerializer<TimeZone>

Serializes TimeZone as timezone identifier string.

@Serializable
data class Meeting(
    @Serializable(with = TimeZoneSerializer::class)
    val timeZone: TimeZone
)

// JSON: {"timeZone": "America/New_York"}

YearMonthIso8601Serializer

object YearMonthIso8601Serializer : KSerializer<YearMonth>

Serializes YearMonth as ISO 8601 year-month string.

@Serializable
data class Report(
    @Serializable(with = YearMonthIso8601Serializer::class)
    val period: YearMonth
)

// JSON: {"period": "2023-12"}

DateTimePeriodIso8601Serializer

object DateTimePeriodIso8601Serializer : KSerializer<DateTimePeriod>

Serializes DateTimePeriod as ISO 8601 period string.

@Serializable
data class Task(
    @Serializable(with = DateTimePeriodIso8601Serializer::class)
    val duration: DateTimePeriod
)

// JSON: {"duration": "P1Y2M3DT4H5M6S"}

DatePeriodIso8601Serializer

object DatePeriodIso8601Serializer : KSerializer<DatePeriod>

Serializes DatePeriod as ISO 8601 date period string.

@Serializable
data class Vacation(
    @Serializable(with = DatePeriodIso8601Serializer::class)
    val length: DatePeriod
)

// JSON: {"length": "P2W"}

MonthIso8601Serializer

object MonthIso8601Serializer : KSerializer<Month>

Serializes Month as ISO 8601 month number (1-12).

@Serializable
data class SeasonalData(
    @Serializable(with = MonthIso8601Serializer::class)
    val month: Month
)

// JSON: {"month": 12}

DayOfWeekSerializer

object DayOfWeekSerializer : KSerializer<DayOfWeek>

Serializes DayOfWeek as ISO day number (1-7, Monday=1).

@Serializable
data class WeeklySchedule(
    @Serializable(with = DayOfWeekSerializer::class)
    val dayOfWeek: DayOfWeek
)

// JSON: {"dayOfWeek": 1}

DateTimeUnitSerializer

object DateTimeUnitSerializer : KSerializer<DateTimeUnit>

Serializes DateTimeUnit with appropriate representation based on unit type.

Component Serializers

These serializers represent datetime values as JSON objects with separate fields for each component.

LocalDateComponentSerializer

object LocalDateComponentSerializer : KSerializer<LocalDate>

Serializes LocalDate as object with year, monthNumber, and dayOfMonth fields.

@Serializable
data class Person(
    @Serializable(with = LocalDateComponentSerializer::class)
    val birthDate: LocalDate
)

// JSON: {"birthDate": {"year": 1990, "monthNumber": 6, "dayOfMonth": 15}}

LocalTimeComponentSerializer

object LocalTimeComponentSerializer : KSerializer<LocalTime>

Serializes LocalTime as object with hour, minute, second, and nanosecond fields.

@Serializable
data class Schedule(
    @Serializable(with = LocalTimeComponentSerializer::class)
    val startTime: LocalTime
)

// JSON: {"startTime": {"hour": 9, "minute": 30, "second": 0, "nanosecond": 0}}

LocalDateTimeComponentSerializer

object LocalDateTimeComponentSerializer : KSerializer<LocalDateTime>

Serializes LocalDateTime as object combining date and time components.

@Serializable
data class Event(
    @Serializable(with = LocalDateTimeComponentSerializer::class)
    val dateTime: LocalDateTime
)

// JSON: {"dateTime": {"year": 2023, "monthNumber": 12, "dayOfMonth": 25, "hour": 14, "minute": 30, "second": 0, "nanosecond": 0}}

YearMonthComponentSerializer

object YearMonthComponentSerializer : KSerializer<YearMonth>

Serializes YearMonth as object with year and monthNumber fields.

@Serializable
data class Report(
    @Serializable(with = YearMonthComponentSerializer::class)
    val period: YearMonth
)

// JSON: {"period": {"year": 2023, "monthNumber": 12}}

DateTimePeriodComponentSerializer

object DateTimePeriodComponentSerializer : KSerializer<DateTimePeriod>

Serializes DateTimePeriod as object with all period components.

@Serializable
data class Task(
    @Serializable(with = DateTimePeriodComponentSerializer::class)
    val duration: DateTimePeriod
)

// JSON: {"duration": {"years": 1, "months": 2, "days": 3, "hours": 4, "minutes": 5, "seconds": 6, "nanoseconds": 0}}

DatePeriodComponentSerializer

object DatePeriodComponentSerializer : KSerializer<DatePeriod>

Serializes DatePeriod as object with date components only.

@Serializable
data class Interval(
    @Serializable(with = DatePeriodComponentSerializer::class)
    val period: DatePeriod
)

// JSON: {"period": {"years": 0, "months": 6, "days": 15}}

Custom Format Serializers

Abstract base classes for creating custom format-based serializers.

LocalDateFormatSerializer

abstract class LocalDateFormatSerializer(
    private val format: DateTimeFormat<LocalDate>
) : KSerializer<LocalDate>

Base class for custom LocalDate serializers using specific formats.

object CustomDateSerializer : LocalDateFormatSerializer(
    LocalDate.Format {
        dayOfMonth(Padding.ZERO)
        char('/')
        monthNumber(Padding.ZERO)
        char('/')
        year()
    }
)

@Serializable
data class Event(
    @Serializable(with = CustomDateSerializer::class)
    val date: LocalDate
)

// JSON: {"date": "25/12/2023"}

LocalTimeFormatSerializer

abstract class LocalTimeFormatSerializer(
    private val format: DateTimeFormat<LocalTime>
) : KSerializer<LocalTime>

Base class for custom LocalTime serializers using specific formats.

LocalDateTimeFormatSerializer

abstract class LocalDateTimeFormatSerializer(
    private val format: DateTimeFormat<LocalDateTime>
) : KSerializer<LocalDateTime>

Base class for custom LocalDateTime serializers using specific formats.

Other Format Serializers

Similar abstract base classes are available for:

  • YearMonthFormatSerializer
  • UtcOffsetFormatSerializer
  • InstantFormatSerializer

Default Serialization

When no explicit serializer is specified, datetime types use their default serializers:

// Default serializers (applied automatically)
@Serializable
data class Event(
    val instant: Instant,           // Uses InstantIso8601Serializer
    val date: LocalDate,            // Uses LocalDateIso8601Serializer
    val time: LocalTime,            // Uses LocalTimeIso8601Serializer
    val dateTime: LocalDateTime,    // Uses LocalDateTimeIso8601Serializer
    val timeZone: TimeZone,         // Uses TimeZoneSerializer
    val period: DateTimePeriod,     // Uses DateTimePeriodIso8601Serializer
    val month: Month,               // Uses MonthIso8601Serializer
    val dayOfWeek: DayOfWeek        // Uses DayOfWeekSerializer
)

Usage Examples

Choosing Serialization Strategy

// ISO 8601 strings - compact, standardized, human-readable
@Serializable
data class EventIso(
    val name: String,
    val startTime: Instant,                    // "2023-12-25T14:30:00Z"
    val date: LocalDate,                       // "2023-12-25"
    val duration: DateTimePeriod               // "PT2H30M"
)

// Component objects - explicit fields, easier for API consumers
@Serializable
data class EventComponents(
    val name: String,
    @Serializable(with = LocalDateComponentSerializer::class)
    val date: LocalDate,                       // {"year": 2023, "monthNumber": 12, "dayOfMonth": 25}
    @Serializable(with = DateTimePeriodComponentSerializer::class)
    val duration: DateTimePeriod               // {"hours": 2, "minutes": 30, ...}
)

// Custom format - domain-specific requirements
object UsDateSerializer : LocalDateFormatSerializer(
    LocalDate.Format {
        monthNumber(Padding.ZERO)
        char('/')
        dayOfMonth(Padding.ZERO)
        char('/')
        year()
    }
)

@Serializable
data class EventCustom(
    val name: String,
    @Serializable(with = UsDateSerializer::class)
    val date: LocalDate                        // "12/25/2023"
)

Collection Serialization

@Serializable
data class Schedule(
    @Serializable(with = LocalTimeIso8601Serializer::class)
    val meetings: List<LocalTime>,
    
    @Serializable(with = DatePeriodComponentSerializer::class)
    val vacations: Map<String, DatePeriod>
)

val schedule = Schedule(
    meetings = listOf(LocalTime(9, 0), LocalTime(14, 30)),
    vacations = mapOf(
        "summer" to DatePeriod(days = 14),
        "winter" to DatePeriod(days = 7)
    )
)

// JSON:
// {
//   "meetings": ["09:00:00", "14:30:00"],
//   "vacations": {
//     "summer": {"years": 0, "months": 0, "days": 14},
//     "winter": {"years": 0, "months": 0, "days": 7}
//   }
// }

Nullable Values

@Serializable
data class OptionalEvent(
    val name: String,
    val startDate: LocalDate?,              // null serializes as null
    val endDate: LocalDate? = null          // default null value
)

Polymorphic Serialization

@Serializable
sealed class TimeRange {
    @Serializable
    data class DateRange(
        val start: LocalDate,
        val end: LocalDate
    ) : TimeRange()
    
    @Serializable
    data class PeriodRange(
        @Serializable(with = DatePeriodIso8601Serializer::class)
        val period: DatePeriod
    ) : TimeRange()
}

Integration with REST APIs

// API request/response DTOs
@Serializable
data class CreateEventRequest(
    val title: String,
    val startTime: Instant,                    // ISO string in JSON
    val duration: DateTimePeriod,              // ISO period string
    val timeZone: TimeZone                     // timezone ID string
)

@Serializable
data class EventResponse(
    val id: String,
    val title: String,
    @Serializable(with = LocalDateTimeComponentSerializer::class)
    val localDateTime: LocalDateTime,          // Component object for frontend
    val timeZone: TimeZone
)

Error Handling

// Deserialization errors are thrown as SerializationException
try {
    val json = """{"date": "invalid-date"}"""
    val event = Json.decodeFromString<EventWithDate>(json)
} catch (e: SerializationException) {
    println("Failed to deserialize: ${e.message}")
}

// For graceful error handling, use nullable fields or custom serializers
@Serializable
data class EventWithOptionalDate(
    val title: String,
    val date: LocalDate? = null  // Will be null if deserialization fails
)

Performance Considerations

  • ISO 8601 serializers are most compact for network transmission
  • Component serializers may be larger but are more explicit for API consumers
  • Custom format serializers should be used sparingly as they may not be as well optimized
  • Consider using @EncodeDefault for optional fields with sensible defaults

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