Exposed时间类型全解析:Java Time vs Joda-Time vs Kotlinx DateTime

【免费下载链接】Exposed Kotlin SQL Framework 【免费下载链接】Exposed 项目地址: https://gitcode.com/gh_mirrors/ex/Exposed

你还在为Kotlin项目选择合适的时间处理方案而烦恼吗?Exposed框架提供了三种时间模块,却不知道它们的区别和适用场景?本文将帮你彻底理清exposed-java-timeexposed-jodatimeexposed-kotlin-datetime的差异,读完你将能够:

  • 掌握三种时间模块的核心特性与适用场景
  • 正确选择符合项目需求的时间处理方案
  • 熟练使用各模块的时间类型与数据库交互

时间模块对比分析

Exposed通过三个独立模块提供时间支持,每个模块基于不同的时间库,适用于不同场景:

模块 基础库 适用场景
exposed-kotlin-datetime kotlinx-datetime 现代Kotlin优先方案,推荐新项目使用
exposed-java-time Java 8 Time API 需与Java代码集成或需要Java时间API兼容性
exposed-jodatime Joda-Time 遗留系统支持,提供额外时间部分提取功能

模块文件路径

基础使用示例

三种模块的表定义语法相似,但导入和时间类型实例化有所区别:

import org.jetbrains.exposed.v1.core.Table

// For exposed-kotlin-datetime (推荐)
import org.jetbrains.exposed.v1.datetime.*

// For exposed-java-time
import org.jetbrains.exposed.v1.javatime.*

// For exposed-jodatime
import org.jetbrains.exposed.v1.jodatime.*

object Events : Table() {
    val id = integer("id").autoIncrement()
    val name = varchar("name", 50)
    val startDate = date("start_date")             // 映射到LocalDate
    val startTime = time("start_time")             // 映射到LocalTime
    val createdAt = datetime("created_at")         // 映射到LocalDateTime
        .defaultExpression(CurrentDateTime)
    val updatedAt = timestamp("updated_at")        // 映射到Instant
    val scheduledAt = timestampWithTimeZone("scheduled_at")  // 映射到OffsetDateTime

    override val primaryKey = PrimaryKey(id)
}

支持的时间类型详解

1. 日期类型 (date())

映射到数据库DATE类型,用于存储无时间部分的日期值:

val birthDate = date("birth_date")

// 使用exposed-kotlin-datetime (推荐)
Events.insert {
    it[birthDate] = LocalDate(1990, 1, 1)
}

// 使用exposed-java-time
Events.insert {
    it[birthDate] = LocalDate.of(1990, 1, 1)
}

// 使用exposed-jodatime
Events.insert {
    it[birthDate] = org.joda.time.LocalDate(1990, 1, 1)
}

2. 日期时间类型 (datetime())

映射到数据库DATETIME类型,存储日期和时间:

val createdAt = datetime("created_at")
    .defaultExpression(CurrentDateTime) // 插入时自动设置当前日期时间

// 使用exposed-kotlin-datetime (推荐)
Events.insert {
    it[createdAt] = Clock.System.now()
        .toLocalDateTime(TimeZone.UTC)
}

// 使用exposed-java-time
Events.insert {
    it[createdAt] = LocalDateTime.now()
}

// 使用exposed-jodatime
Events.insert {
    it[createdAt] = DateTime.now()
}

注意:使用exposed-jodatime时,可以使用year()month()day()hour()minute()second()函数提取时间部分

3. 时间类型 (time())

映射到数据库TIME类型,存储无日期部分的时间值:

val startTime = time("start_time")

// 使用exposed-kotlin-datetime (推荐)
Events.insert {
    it[startTime] = LocalTime(9, 0) // 09:00
}

// 使用exposed-java-time
Events.insert {
    it[startTime] = LocalTime.of(9, 0) // 09:00
}

// 使用exposed-jodatime
Events.insert {
    it[startTime] = org.joda.time.LocalTime(9, 0) // 09:00
}

4. 时间戳类型 (timestamp())

映射到数据库TIMESTAMP类型,不支持exposed-jodatime

val lastModified = timestamp("last_modified")

// 使用exposed-kotlin-datetime (推荐)
Events.insert {
    it[lastModified] = Clock.System.now()
}

// 使用exposed-java-time
Events.insert {
    it[lastModified] = Instant.now()
}

5. 带时区时间戳 (timestampWithTimeZone())

映射到数据库TIMESTAMP WITH TIME ZONE类型,不支持exposed-jodatime

val scheduledAt = timestampWithTimeZone("scheduled_at")

// 使用exposed-kotlin-datetime (推荐)
Events.insert {
    it[scheduledAt] = Clock.System.now().toOffsetDateTime(TimeZone.UTC)
}

// 使用exposed-java-time
Events.insert {
    it[scheduledAt] = OffsetDateTime.now(ZoneOffset.UTC)
}

警告:PostgreSQL和MySQL会将时间戳存储为UTC,从而丢失原始时区信息。要在这些数据库中保留原始时区,需将时区信息存储在单独的列中。

类型支持对比

三种模块支持的时间类型有所不同,以下是详细对比:

类型 exposed-kotlin-datetime exposed-java-time exposed-jodatime
date() 支持 (LocalDate) 支持 (LocalDate) 支持 (LocalDate)
time() 支持 (LocalTime) 支持 (LocalTime) 支持 (LocalTime)
datetime() 支持 (LocalDateTime) 支持 (LocalDateTime) 支持 (DateTime)
timestamp() 支持 (Instant) 支持 (Instant) 不支持
timestampWithTimeZone() 支持 (OffsetDateTime) 支持 (OffsetDateTime) 不支持

项目选择指南

推荐使用exposed-kotlin-datetime的场景

  • 新建Kotlin项目
  • 无需与Java时间API交互
  • 需要现代、简洁的Kotlin风格API
  • 关注未来兼容性和框架推荐方案

推荐使用exposed-java-time的场景

  • 需要与Java代码或库集成
  • 团队更熟悉Java Time API
  • 项目中已有大量Java时间类型使用

推荐使用exposed-jodatime的场景

  • 维护遗留系统
  • 需要时间部分提取功能
  • 项目已深度使用Joda-Time库

实践示例:事件调度系统

假设我们正在构建一个事件调度系统,需要存储不同时区的事件时间。使用exposed-kotlin-datetime模块的实现如下:

import org.jetbrains.exposed.v1.core.Database
import org.jetbrains.exposed.v1.datetime.*
import org.jetbrains.exposed.v1.sql.*
import org.jetbrains.exposed.v1.sql.transactions.transaction
import kotlinx.datetime.Clock
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toOffsetDateTime

object Events : Table() {
    val id = integer("id").autoIncrement()
    val title = varchar("title", 100)
    val startTime = datetime("start_time")
    val endTime = datetime("end_time")
    val scheduledAt = timestampWithTimeZone("scheduled_at")
    
    override val primaryKey = PrimaryKey(id)
}

fun main() {
    Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver")
    
    transaction {
        SchemaUtils.create(Events)
        
        val now = Clock.System.now()
        
        Events.insert {
            it[title] = "Kotlin Meetup"
            it[startTime] = now.toLocalDateTime(TimeZone.of("Asia/Shanghai"))
            it[endTime] = now.toLocalDateTime(TimeZone.of("Asia/Shanghai")).plusHours(2)
            it[scheduledAt] = now.toOffsetDateTime(TimeZone.of("Asia/Shanghai"))
        }
        
        // 查询今天的事件
        val today = Clock.System.now().toLocalDate(TimeZone.currentSystemDefault())
        val todayEvents = Events.select { 
            Events.startTime greaterEq today.atStartOfDay() and 
            Events.startTime lessEq today.atEndOfDay()
        }
        
        println("今天的事件:")
        todayEvents.forEach {
            println("${it[Events.title]}: ${it[Events.startTime]}")
        }
    }
}

总结与最佳实践

  1. 优先选择官方推荐的exposed-kotlin-datetime:作为现代Kotlin项目的首选,提供最简洁的API和最佳的未来兼容性。

  2. 注意时区处理:始终明确指定时区,避免依赖系统默认时区导致的问题。

  3. 合理设计时间列

    • 仅需日期时使用date()
    • 本地时间使用datetime()
    • 跨时区时间使用timestampWithTimeZone()
    • 记录修改时间使用timestamp()并设置默认值
  4. 避免混合使用不同模块:项目中坚持使用一种时间模块,避免类型转换复杂性。

通过本文的介绍,你已经了解了Exposed三种时间模块的核心差异和使用方法。选择合适的时间处理方案,将为你的项目带来更好的可维护性和性能。如有更多疑问,可以查阅官方时间类型文档或Exposed示例项目:samples/

希望本文对你有所帮助!如果你觉得内容有价值,请点赞收藏,关注获取更多Exposed使用技巧。下期我们将探讨Exposed中的事务管理最佳实践。

【免费下载链接】Exposed Kotlin SQL Framework 【免费下载链接】Exposed 项目地址: https://gitcode.com/gh_mirrors/ex/Exposed

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐