1. 概述

在Java中处理时间戳是常见任务,尤其是在操作数据库或开发全球化应用时。两个核心类——java.sql.Timestamporg.joda.time.DateTime——分别承担着不同的时间处理职责。

本文将探讨在Java中转换这两种时间类型的三种主流方法,并附上可直接运行的代码示例。⚠️ 注意:所有方案都基于JDK 8+和Joda-Time 2.x版本。

2. 将java.sql.Timestamp转换为org.joda.time.DateTime

2.1. 使用构造函数转换

这是最简单粗暴的方式——直接通过Timestamp的毫秒值创建DateTime对象:

DateTime convertToDateTimeUsingConstructor(Timestamp timestamp) {
    return new DateTime(timestamp.getTime());
}

测试用例验证:

@Test
public void givenTimestamp_whenUsingConstructor_thenConvertToDateTime() {
    long currentTimeMillis = System.currentTimeMillis();
    Timestamp timestamp = new Timestamp(currentTimeMillis);
    DateTime expectedDateTime = new DateTime(currentTimeMillis);
    DateTime convertedDateTime = DateTimeAndTimestampConverter.convertToDateTimeUsingConstructor(timestamp);
    assertEquals(expectedDateTime, convertedDateTime);
}

✅ 优点:代码极简,性能最优
❌ 缺点:依赖系统默认时区,跨时区场景需谨慎

2.2. 使用Instant类转换

Instant表示UTC时间轴上的一个绝对时间点,非常适合作为中间桥梁:

DateTime convertToDateTimeUsingInstant(Timestamp timestamp) {
    Instant instant = timestamp.toInstant();
    return new DateTime(instant.toEpochMilli());
}

核心步骤拆解:

  1. timestamp.toInstant() → 转换为UTC时间点
  2. instant.toEpochMilli() → 获取Unix纪元毫秒数
  3. 构造DateTime对象

测试验证:

@Test
public void givenTimestamp_whenUsingInstant_thenConvertToDateTime() {
    long currentTimeMillis = System.currentTimeMillis();
    Timestamp timestamp = new Timestamp(currentTimeMillis);
    DateTime expectedDateTime = new DateTime(currentTimeMillis);
    DateTime convertedDateTime = DateTimeAndTimestampConverter.convertToDateTimeUsingInstant(timestamp);
    assertEquals(expectedDateTime, convertedTimestamp);
}

⚠️ 注意:此方案最终仍使用系统默认时区,若需指定时区需额外处理

2.3. 使用LocalDateTime类转换

Java 8引入的LocalDateTime不包含时区信息,需配合ZoneId使用:

DateTime convertToDateTimeUsingLocalDateTime(Timestamp timestamp) {
    LocalDateTime localDateTime = timestamp.toLocalDateTime();
    return new DateTime(localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
}

执行流程:

  1. timestamp.toLocalDateTime() → 转为无时区日期时间
  2. .atZone(ZoneId.systemDefault()) → 绑定系统时区
  3. 转换为Instant再获取毫秒数

测试用例:

@Test
public void givenTimestamp_whenUsingLocalDateTime_thenConvertToDateTime() {
    long currentTimeMillis = System.currentTimeMillis();
    Timestamp timestamp = new Timestamp(currentTimeMillis);
    DateTime expectedDateTime = new DateTime(currentTimeMillis);
    DateTime convertedDateTime = DateTimeAndTimestampConverter.convertToDateTimeUsingLocalDateTime(timestamp);
    assertEquals(expectedDateTime, convertedDateTime);
}

🔧 适用场景:需要显式控制时区转换逻辑时

3. 将org.joda.time.DateTime转换为java.sql.Timestamp

3.1. 使用构造函数转换

反向操作同样简单,直接获取DateTime的毫秒值构造Timestamp

Timestamp convertToTimestampUsingConstructor(DateTime dateTime) {
    return new Timestamp(dateTime.getMillis());
}

测试验证:

@Test
public void givenDateTime_whenUsingConstructor_thenConvertToTimestamp() {
    long currentTimeMillis = System.currentTimeMillis();
    DateTime dateTime = new DateTime(currentTimeMillis);
    Timestamp expectedTimestamp = new Timestamp(currentTimeMillis);
    Timestamp convertedTimestamp = DateTimeAndTimestampConverter.convertToTimestampUsingConstructor(dateTime);
    assertEquals(expectedTimestamp, convertedTimestamp);
}

✅ 优势:零中间对象,性能最佳
❌ 局限:隐式使用系统时区

3.2. 使用Instant类转换

通过Instant作为中间媒介实现转换:

Timestamp convertToTimestampUsingInstant(DateTime dateTime) {
    Instant instant = Instant.ofEpochMilli(dateTime.getMillis());
    return Timestamp.from(instant);
}

关键步骤:

  1. dateTime.getMillis() → 获取毫秒值
  2. Instant.ofEpochMilli() → 创建UTC时间点
  3. Timestamp.from() → 生成时间戳对象

测试用例:

@Test
public void givenDateTime_whenUsingInstant_thenConvertToTimestamp() {
    long currentTimeMillis = System.currentTimeMillis();
    DateTime dateTime = new DateTime(currentTimeMillis);
    Timestamp expectedTimestamp = new Timestamp(currentTimeMillis);
    Timestamp convertedTimestamp = DateTimeAndTimestampConverter.convertToTimestampUsingInstant(dateTime);
    assertEquals(expectedTimestamp, convertedTimestamp);
}

💡 提示:此方案比构造函数方式更符合Java 8+的时间API设计理念

3.3. 使用LocalDateTime类转换

适用于需要处理本地日期时间的场景:

Timestamp convertToTimestampUsingLocalDateTime(DateTime dateTime) {
    Instant instant = Instant.ofEpochMilli(dateTime.getMillis());
    LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    return Timestamp.valueOf(localDateTime);
}

转换流程:

  1. 创建Instant对象
  2. 转换为系统默认时区的LocalDateTime
  3. 通过Timestamp.valueOf()生成目标对象

测试验证:

@Test
public void givenDateTime_whenUsingLocalDateTime_thenConvertToTimestamp() {
    long currentTimeMillis = System.currentTimeMillis();
    DateTime dateTime = new DateTime(currentTimeMillis);
    Timestamp expectedTimestamp = new Timestamp(currentTimeMillis);
    Timestamp convertedTimestamp = DateTimeAndTimestampConverter.convertToTimestampUsingLocalDateTime(dateTime);
    assertEquals(expectedTimestamp, convertedTimestamp);
}

⚠️ 踩坑预警:LocalDateTime不包含时区信息,若时区处理不当会导致时间偏差

4. 总结

转换方向 推荐方案 适用场景
Timestamp → DateTime 构造函数 简单场景,性能优先
Timestamp → DateTime Instant 需要UTC时间点处理
DateTime → Timestamp 构造函数 基础转换需求
DateTime → Timestamp Instant 符合Java 8+ API风格

💎 核心结论:

  1. 构造函数方案最简单高效,但隐含时区风险
  2. Instant方案更符合现代Java时间API设计
  3. LocalDateTime方案适用于需要显式时区控制的复杂场景

完整代码示例可在GitHub仓库获取,或联系作者:contact@baeldung.com


原始标题:Convert Between org.joda.time.DateTime and java.sql.Timestamp in Java | Baeldung