美文网首页
pg数据库保存本地时间时区丢失问题

pg数据库保存本地时间时区丢失问题

作者: flystarts | 来源:发表于2024-09-03 14:26 被阅读0次

pg数据库有timestamptz字段类型可以用来保存带时区的时间
在实体定义里采用OffsetDateTime 来定义字段
dao层使用mybatis-plus框架

写入指定时区的时间:"2024-04-05T00:00:00+02:00"
但是数据库里变成了 2024-04-05 06:00:00.000 +0800
很显然,时间被转成了+8时区,这不是我们希望的效果

为了解决此问题,在网上找了很多解决办法,其中较多的是说要自定义typehandler,于是我自定义了
OffsetDateTimeTypeHandler:

@Override
    public void setNonNullParameter(PreparedStatement ps, int i, OffsetDateTime parameter, JdbcType jdbcType) throws SQLException {
        ps.setTimestamp(i, java.sql.Timestamp.from(parameter.toInstant()));
    }

测试发现没解决问题,查看Timestamp类的定义,发现他根本就不支持时区,所以必然导致时区丢失

后来又改为ps.setObject,

@Override
    public void setNonNullParameter(PreparedStatement ps, int i, OffsetDateTime parameter, JdbcType jdbcType) throws SQLException {
        //ps.setTimestamp(i, java.sql.Timestamp.from(parameter.toInstant()));
        ps.setObject(i, parameter);
    }

但是都不能解决问题。后来走读代码,发现mybatis自带的OffsetDateTimeTypeHandler也是这么写的,所以这里自定义typehandler不能解决问题

为了找到问题原因,我先用jdbc试一下

 // 时间和时区
        OffsetDateTime dateTimeWithZone = OffsetDateTime.parse("2024-04-04T00:00:00+02:00");
        System.out.println(dateTimeWithZone);// 默认时区
        Timestamp timestampWithZone = Timestamp.from(dateTimeWithZone.toInstant());

        try (Connection conn = DriverManager.getConnection(url, user, password);
             PreparedStatement pstmt = conn.prepareStatement("INSERT INTO newtable (time) VALUES (?)")) {

            // 设置时间戳
            pstmt.setTimestamp(1, timestampWithZone);  
            //pstmt.setObject(1, dateTimeWithZone);

            // 执行更新
            pstmt.executeUpdate();

            System.out.println("时间已保存到数据库");

        } catch (SQLException e) {
            e.printStackTrace();
        }
image.png

调试发现代码走到这里已经丢失了时区

看Timestamp的定义,发现这个类根本就不支持带时区,所以如果用pstmt.setTimestamp来写,肯定会丢失时区
接下来尝改为setObject,发现最后写到数据库里的时间还是改变了时区

通过代码调试,在pg数据库驱动代码里,SimpleParameterList: writeV3Value

image.png

这里把时间字符串 2024-04-04 00:00:00+02 转成bytes保存了然后调用pgStream.send

可见数据库客户端发过去的是这样的字符串2024-04-04 00:00:00+02

那为什么最后数据库保存的变成了+8呢? 这就需要看数据库服务端的实现了

综上,jdbc写时间的时候,客户端侧并没有改变时区,所以问题还在服务端。因此,在应用层,mybatis层面是无法解决问题的,当前只能先在应用层规避,即自己去做时区转换。

相关文章

  • JDK不同版本时区问题

    1、问题描述 项目中通过时区名称转换为本地时间(JDK11.0.1),与数据库(Postgresql12.3)转换...

  • pg_dump用法

    导出库 pg_dump 数据库名>保存目录 恢复

  • 工作笔记

    1、在保存时间的时候要注意数据库的时区,在工作的时候出现了,保存时间出现时间少13个小时的情况, 2、spring...

  • 游戏时区问题小解

    由于时区、夏令时的存在,游戏内的时间显示/计算都要考虑时区问题并进行相应处理。时间计算不用说,要排除玩家本地时区影...

  • Heroku本地数据库和远程数据库

    pg:pull pg:pull命令可以用来把数据从Heroku的数据库拉到本地,命令的形式为:$ heroku p...

  • Oracle SQL 学习笔记16 - 日期和时间

    TIME_ZONE 这是一个会话参数,可以设置为 绝对偏移量 数据库时区 操作系统本地时区 时区名称 CURREN...

  • 2019-10-03 UTC、GMT时区转换工具

    1.本地时间 => UTC 2.UTC => 本地时间 3.UTC => 指定时区时间

  • MySQL数据库修改时间、时区

    MySQL数据库修改时间、时区 mysql默认使用的SYSTEM时区,即EST时区,查询相关资料可知,EST时区要...

  • Mysql更新时区表

    时区问题 Django项目做了数据库迁移后有时候出现时区上的问题,例如django项目中设置的时区是TIME_Z...

  • 服务器修改时区

    查看服务器时间 修改时区 方法一 : 方法二 : 注意,修改时区后,若数据库是之前时区启动的,需要重启数据库

网友评论

      本文标题:pg数据库保存本地时间时区丢失问题

      本文链接:https://www.haomeiwen.com/subject/sdbkljtx.html