You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Kotlinx DateTime类型配置MongoDB官方Kotlin驱动的编解码器

如何为Kotlinx DateTime类型配置MongoDB官方Kotlin驱动的编解码器

我完全懂你现在的困扰——官方MongoDB Kotlin驱动默认不认识kotlinx.datetime里的Instant和LocalDateTime类型,这才导致了那个找不到编解码器的异常。下面给你两种实用的解决方案,你可以根据项目情况挑合适的来用:

方案一:使用官方提供的Kotlinx DateTime编解码器扩展

MongoDB官方针对kotlinx.datetime类型提供了现成的编解码器支持,只需要添加对应依赖并配置即可:

1. 添加依赖(以Gradle Kotlin DSL为例)

在你的build.gradle.kts中加入以下依赖(请替换为对应版本的驱动):

implementation("org.mongodb:mongodb-kotlin-driver-kotlinx:4.11.1")

2. 配置MongoClient时注册编解码器

创建MongoClient实例时,把官方的Kotlinx编解码器提供者加入到CodecRegistry中:

import com.mongodb.kotlin.client.coroutine.MongoClient
import org.mongodb.kotlin.driver.kotlinx.KotlinxCodecProvider
import org.bson.codecs.configuration.CodecRegistries

val mongoClient = MongoClient.create("你的MongoDB连接字符串") {
    codecRegistry = CodecRegistries.fromRegistries(
        MongoClient.getDefaultCodecRegistry(),
        CodecRegistries.fromProviders(KotlinxCodecProvider())
    )
}

这样配置后,驱动就能自动处理kotlinx.datetime的Instant和LocalDateTime类型了,不用自己写额外代码。

方案二:自定义编解码器

如果不想引入额外依赖,或者需要更定制化的编解码逻辑,你可以自己实现Codec接口:

1. 实现Instant的编解码器

import org.bson.BsonReader
import org.bson.BsonWriter
import org.bson.codecs.Codec
import org.bson.codecs.DecoderContext
import org.bson.codecs.EncoderContext
import kotlinx.datetime.Instant
import kotlinx.datetime.toJavaInstant

class KotlinxInstantCodec : Codec<Instant> {
    override fun encode(writer: BsonWriter, value: Instant, encoderContext: EncoderContext) {
        // 把kotlinx Instant转成Java Instant,再写入时间戳
        val javaInstant = value.toJavaInstant()
        writer.writeDateTime(javaInstant.toEpochMilli())
    }

    override fun getEncoderClass(): Class<Instant> = Instant::class.java

    override fun decode(reader: BsonReader, decoderContext: DecoderContext): Instant {
        // 读取时间戳并转成kotlinx Instant
        val epochMilli = reader.readDateTime()
        return Instant.fromEpochMilliseconds(epochMilli)
    }
}

2. 实现LocalDateTime的编解码器

注意:LocalDateTime本身不带时区信息,这里提供两种存储方式,你可以根据业务需求选择:

方式A:存储为ISO字符串(无时区问题)

import org.bson.BsonReader
import org.bson.BsonWriter
import org.bson.codecs.Codec
import org.bson.codecs.DecoderContext
import org.bson.codecs.EncoderContext
import kotlinx.datetime.LocalDateTime

class KotlinxLocalDateTimeCodec : Codec<LocalDateTime> {
    override fun encode(writer: BsonWriter, value: LocalDateTime, encoderContext: EncoderContext) {
        // 转成ISO标准字符串存储
        writer.writeString(value.toString())
    }

    override fun getEncoderClass(): Class<LocalDateTime> = LocalDateTime::class.java

    override fun decode(reader: BsonReader, decoderContext: DecoderContext): LocalDateTime {
        // 读取字符串并解析为LocalDateTime
        val ldtString = reader.readString()
        return LocalDateTime.parse(ldtString)
    }
}

方式B:存储为时间戳(需处理时区)

如果需要用时间戳存储,必须指定时区转换,避免读取时出现偏差:

import org.bson.BsonReader
import org.bson.BsonWriter
import org.bson.codecs.Codec
import org.bson.codecs.DecoderContext
import org.bson.codecs.EncoderContext
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
import kotlinx.datetime.toLocalDateTime

class KotlinxLocalDateTimeCodec : Codec<LocalDateTime> {
    private val timeZone = TimeZone.currentSystemDefault() // 或者指定固定时区,比如TimeZone.UTC

    override fun encode(writer: BsonWriter, value: LocalDateTime, encoderContext: EncoderContext) {
        // 转成带时区的Instant再写入时间戳
        val instant = value.toInstant(timeZone)
        writer.writeDateTime(instant.toEpochMilliseconds())
    }

    override fun getEncoderClass(): Class<LocalDateTime> = LocalDateTime::class.java

    override fun decode(reader: BsonReader, decoderContext: DecoderContext): LocalDateTime {
        // 读取时间戳并转成对应时区的LocalDateTime
        val epochMilli = reader.readDateTime()
        val instant = Instant.fromEpochMilliseconds(epochMilli)
        return instant.toLocalDateTime(timeZone)
    }
}

3. 注册自定义编解码器到MongoClient

import com.mongodb.kotlin.client.coroutine.MongoClient
import org.bson.codecs.configuration.CodecRegistries

val customCodecRegistry = CodecRegistries.fromCodecs(
    KotlinxInstantCodec(),
    KotlinxLocalDateTimeCodec()
)

val mongoClient = MongoClient.create("你的MongoDB连接字符串") {
    codecRegistry = CodecRegistries.fromRegistries(
        MongoClient.getDefaultCodecRegistry(),
        customCodecRegistry
    )
}

两种方案都能解决你遇到的编解码器问题,优先推荐方案一,毕竟官方维护的扩展更稳定省心;如果有特殊需求,再考虑自定义编解码器。

备注:内容来源于stack exchange,提问作者Eel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 09:29:35