Kotlinx.Serialization deserializing dates
Asked Answered
R

3

10

I'm having a hard time finding documentation on how to deserialize date fields. How do i achieve this? Most solutions i found on SO don't work or they use classes that are no longer available

@Serializable
data class Dashboard(
    val someNumber: Int,
    val someDate: Date? // Custom Deserialization from unix timestamp
)

EDIT: Most solution i found use PrimitiveSerialDescriptor which seems to be not available

Ruck answered 28/4, 2021 at 18:21 Comment(5)
I believe you should write a customer serializer (example).Contemporaneous
@Contemporaneous it uses Unresolved reference: PrimitiveSerialDescriptor which doesn't resolveRuck
Did you add the corresponding import import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor?Pani
"Custom Deserialization from unix timestamp" In that case just declare it as a Long. Conversions is not what a @Serializable is for.Selfdriven
seems like PrimitiveSerialDescriptor is available only after 1.0.0+ library versionFachini
M
17

Do not use Date, but use Instant or LocalDateTime instead, you need to add this in build.gradle file

implementation "org.jetbrains.kotlinx:kotlinx-datetime:0.3.2"

read more about it in this link: https://github.com/Kotlin/kotlinx-datetime

This will automatically Serializable and also work in KMM 😀

Morocco answered 6/2, 2022 at 11:13 Comment(5)
This isn't working when trying to serialize .NET DateTimeMicrometry
@tom-williamI can't exactly help the API is written in C#, we don't get to choose what the API is written inMicrometry
@Micrometry I know, then you should not ask here, you should make new articles and ask about C# serialization because this is only about Kotlin serialization. 😁Morocco
seeing as my android app is written in kotlin, I thought it was fitting, but I figured it out anyway :PMicrometry
After adding that library I'm still getting the message "Serializer has not been found for type 'LocalDateTime'". Is there any additional setup needed? Edit: found the issue, it needs to be kotlinx.datetime.LocalDateTimeKronick
E
11

There is good documentation for the latest version of kotlinx.serialization https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md#custom-serializers

However, there is no PrimitiveSerialDescriptor class in the question which means, that some older version of kotlinx.serialization is used.

From https://github.com/Kotlin/kotlinx.serialization/releases it could be found out that in version 1.0.0-RC

PrimitiveDescriptor was renamed to PrimitiveSerialDescriptor

and

The id of the core artifact with @Serializable annotation and Json format was changed from kotlinx-serialization-runtime to kotlinx-serialization-core to be more clear and aligned with other kotlinx libraries.

Following that, here is an example of code for kotlinx.serialization version 0.20.0:

object DateSerializer : KSerializer<Date> {
    override val descriptor = PrimitiveDescriptor("Date", PrimitiveKind.LONG)
    override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time)
    override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong())
}

@Serializable
data class MyDto(
    @Serializable(DateSerializer::class)
    val date: Date
)

fun main() {
    val dto = Json.parse(MyDto.serializer(), """{ "date" : 1630407000000 }""")
    println(dto.date)
}

with build.gradle.kts

plugins {
    kotlin("jvm") version "1.3.72"
    kotlin("plugin.serialization") version "1.3.72"
}
repositories { mavenCentral() }
dependencies {
    implementation("org.jetbrains.kotlinx", "kotlinx-serialization-runtime", "0.20.0")
}
Envelopment answered 31/8, 2021 at 12:23 Comment(0)
G
4

To deserialize

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale


@OptIn(ExperimentalSerializationApi::class)
@Serializer(forClass = Date::class)
object DateSerializer {
    private val format = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)

    override fun deserialize(decoder: Decoder): Date {
        val dateString = decoder.decodeString()
        return format.parse(dateString)
    }

    override fun serialize(encoder: Encoder, value: Date) {
        val dateString = format.format(value)
        encoder.encodeString(dateString)
    }
}

then in your @Serializable class,

@Serializable(with = DateSerializer::class)
val date: Date,

the dependencies at app level build.gradle file.

implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0'

you may need to play around with the format "yyyy-MM-dd" as this answer deals with 2023-June-05 format.

Gast answered 2/6, 2023 at 16:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.