6

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

aryaxt
  • 76,198
  • 92
  • 293
  • 442
  • I believe you should write a customer serializer ([example](https://proandroiddev.com/custom-kotlinx-serializers-cd148e72d712)). – azizbekian Apr 28 '21 at 18:29
  • @azizbekian it uses `Unresolved reference: PrimitiveSerialDescriptor` which doesn't resolve – aryaxt Apr 28 '21 at 18:31
  • Did you add the corresponding import `import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor`? – pixix4 Apr 28 '21 at 21:10
  • "Custom Deserialization from unix timestamp" In that case just declare it as a `Long`. Conversions is not what a @Serializable is for. – xjcl Apr 29 '21 at 09:43
  • seems like PrimitiveSerialDescriptor is available only after 1.0.0+ library version – Sandesh Baliga Jul 22 '21 at 10:47

3 Answers3

9

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")
}
6

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

Tom William
  • 81
  • 1
  • 3
  • 1
    This isn't working when trying to serialize .NET DateTime – Eman May 02 '22 at 20:42
  • @tom-williamI can't exactly help the API is written in C#, we don't get to choose what the API is written in – Eman May 04 '22 at 14:15
  • 1
    @Eman 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. – Tom William May 05 '22 at 19:22
  • 2
    seeing as my android app is written in kotlin, I thought it was fitting, but I figured it out anyway :P – Eman May 05 '22 at 19:33
  • 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.LocalDateTime – Wrakor Mar 27 '23 at 16:29
1

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.

All Іѕ Vаиітy
  • 24,861
  • 16
  • 87
  • 111