【问题标题】:How to use Joda-Time with java.sql.Timestamp如何将 Joda-Time 与 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 文档,但没有看到对此的参考。

谢谢。

【问题讨论】:

    标签: java postgresql timestamp jodatime


    【解决方案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 类。
    猜你喜欢
    • 1970-01-01
    • 2013-03-04
    • 2012-06-22
    • 2012-12-11
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    • 2015-05-22
    • 2016-06-19
    相关资源
    最近更新 更多