A multiplatform Kotlin library for working with date and time with JVM target 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.
kotlinx-datetime provides comprehensive serialization support through kotlinx.serialization, offering multiple serialization strategies:
These serializers represent datetime values as ISO 8601 standard strings.
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"}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"}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"}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"}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"}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"}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"}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"}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}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}object DateTimeUnitSerializer : KSerializer<DateTimeUnit>Serializes DateTimeUnit with appropriate representation based on unit type.
These serializers represent datetime values as JSON objects with separate fields for each component.
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}}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}}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}}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}}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}}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}}Abstract base classes for creating custom format-based serializers.
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"}abstract class LocalTimeFormatSerializer(
private val format: DateTimeFormat<LocalTime>
) : KSerializer<LocalTime>Base class for custom LocalTime serializers using specific formats.
abstract class LocalDateTimeFormatSerializer(
private val format: DateTimeFormat<LocalDateTime>
) : KSerializer<LocalDateTime>Base class for custom LocalDateTime serializers using specific formats.
Similar abstract base classes are available for:
YearMonthFormatSerializerUtcOffsetFormatSerializerInstantFormatSerializerWhen 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
)// 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"
)@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}
// }
// }@Serializable
data class OptionalEvent(
val name: String,
val startDate: LocalDate?, // null serializes as null
val endDate: LocalDate? = null // default null value
)@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()
}// 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
)// 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
)@EncodeDefault for optional fields with sensible defaultsInstall with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlinx--kotlinx-datetime-jvm