如何将 Joda-Time 与 java.sql.Timestamp 一起使用
Posted
技术标签:
【中文标题】如何将 Joda-Time 与 java.sql.Timestamp 一起使用【英文标题】:How to use Joda-Time with java.sql.Timestamp 【发布时间】:2010-11-07 11:49:48 【问题描述】:我有一个prepared statement
INSERT INTO mst(time) VALUES (?);
PostgreSQL 数据库中的时间类型为 Timestamp。 我正在插入一个 Joda-Time DateTime 对象,或者我应该说我正在尝试。我找不到将 DateTime 对象转换为java.sql.Timestamp 的方法。我已阅读 Joda-Time 文档,但没有看到对此的参考。
谢谢。
【问题讨论】:
【参考方案1】:您可以先将 Joda DateTime 转换为 long(自纪元以来的毫秒数),然后从中创建时间戳。
DateTime dateTime = new DateTime();
Timestamp timeStamp = new Timestamp(dateTime.getMillis());
【讨论】:
TimeZone 组件在哪里?您只“复制”了日期和时间,而不是可能影响实际值的时区... 你能详细说明你的意思吗? dateTime.getMillis() 返回自纪元以来的毫秒数,其中考虑了时区。 值得注意的是,joda-time 不存储纳秒,而 Timestamp 存储。两者之间的任何转换都会损失纳秒级精度。 @Jack Leow 他的意思是,如果 DateTime 有一个时区使日期在午夜更改一天,那么使用松散时区的时间戳可以让日期回到一天.这就是你如何让 DAO 单元测试只在午夜左右失败:-) 为了后代,如果您需要将时间戳转换为 Joda DateTime,new DateTime(timeStamp.getTime())
。【参考方案2】:
JodaTime 的 DateTime 构造函数现在可以为您处理这个问题。 (我不确定这个问题发布时是否属实,但这是 Google 的***搜索结果,所以我想我会添加一个更新的解决方案。)
有几个 API 选项:
public DateTime(Object instant);
public DateTime(Object instant, DateTimeZone zone);
两个选项都接受 java.sql.Timestamp,因为它扩展了 java.util.Date,但纳秒将被忽略(下限),因为 DateTime 和 Date 只有毫秒分辨率*。如果没有特定的时区,它将默认为 DateTimeZone.UTC。
“分辨率”是提供了多少位数。 “精度”是表示的准确程度。例如,MSSQL 的 DateTime 具有毫秒分辨率,但只有 ~1/3 秒精度(DateTime2 具有可变分辨率和更高的精度)。教学模式>
具有毫秒分辨率的 UTC 时间戳示例:
new DateTime(resultSet.getTimestamp(1));
如果您在数据库中使用 TIMESTAMP WITH TIME ZONE,则不能使用 java.sql.Timestamp,因为它不支持时区。您必须使用 ResultSet#getString 并解析字符串。
不带时区的时间戳,第二分辨率示例**:
LocalDateTime dt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
.parseLocalDateTime(resultSet.getString(1));
具有第二分辨率示例的 UTC 时间戳**:
DateTime dt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
.parseDateTime(resultSet.getString(1));
带时区的时间戳(偏移格式)和第二分辨率示例**:
DateTime dt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z")
.parseDateTime(resultSet.getString(1));
奖励:DateTimeFormat#forPattern 按模式静态缓存解析器,因此您不必这样做。
我通常建议在您的 DBO 模型中使用字符串,以便明确解析并避免生成中间对象。 (2013-11-14 09:55:25 是否等于 2013-11-14 09:55:25.000?)我通常会尝试区分针对数据保存问题进行优化的“数据库模型对象”和针对数据保存问题进行优化的“业务模型对象”服务级别的使用,中间有一个转换/映射层。我发现让基于 CRUD 的 DAO 直接生成业务对象往往会混淆优先级并针对两者进行优化,由于错过了边缘情况而从意想不到的地方抛出异常。拥有显式转换层还允许您在必要时添加验证,例如如果您不控制数据源。分离关注点还可以更轻松地独立测试每一层。教学模式>
* 如果您需要在业务模型中解析到纳秒级分辨率,则必须使用不同的库。
** 时间戳字符串格式可能因数据库而异,不确定。
【讨论】:
关于纳秒...仅供参考,JSR 310: Date and Time API 被内置到 Java 8 中,以及 Joda-Time 的继任者,确实支持纳秒分辨率。请记住,许多计算机的时钟无法保持时间的粒度。另外:来自 JSR 规范的有趣注释:这些类使用纳秒精度。这些类具有足够的精度来表示当前宇宙年龄内的任何纳秒瞬间。 我希望他们能更正该规范中的措辞……Java 无法控制硬件的精度,而准确性是精度和正确性(或“真实性”)的函数。这些类具有纳秒分辨率和足够的内存大小来表示非常大量的纳秒。 至于您对粒度的断言:有些系统没有纳秒级分辨率,有些系统没有纳秒级精度或正确性。 System.nanoTime() 可能会在操作系统不提供纳秒分辨率的任何系统上添加零,但这只会增加分辨率,而不是精度、正确性或准确性。这是我能找到的关于术语的最详尽的来源:tutelman.com/golf/measure/precision.php 我不明白你的说法,If you're using TIMESTAMP WITH TIME ZONE in your database then you can't use java.sql.Timestamp
。尽管名称具有误导性,TIMESTAMP WITH TIME ZONE
类型实际上并不存储任何时区信息。该类型在插入和检索日期时间值时会考虑时区,但始终将值存储为 UTC。因此,我们可以检索 TIMESTAMP WITH TIME ZONE
值作为 JDBC 类型 java.sql.Timestamp
对象,以提供给 org.joda.time.DateTime
实例的构造函数。我使用now()
函数进行了测试。
仅供参考:Joda-Time 项目现在位于 maintenance mode,建议迁移到 java.time 类。以上是关于如何将 Joda-Time 与 java.sql.Timestamp 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
Java Joda-Time ,将 LocalDate 分配给 Month 和 Year