如何通过JDBC Oracle驱动获取Oracle数据库中无时区调整的DATE?
问题
执行以下代码读取Oracle 21c数据库的DATE字段时:
java.sql.Date date = resultSet.getDate("DATE_COLUMN"); // 假设数据库中存储的是'16/05/1993'
Oracle JDBC驱动会在后台自动做时区调整,最终java.sql.Date内部的UNIX时间戳可能和预期的16/05/1993 00:00:00 UTC不一致——比如原本的'16/05/1993'传到应用里可能变成'15/05/1993'。
现在需要获取DATE字段的原始形式,满足以下任一要求即可:
- 直接拿到日、月、年三个独立数值(比如日=16,月=5,年=1993)
- 得到的时间戳始终对应16/05/1993 00:00:00 UTC
有没有办法避免这种不必要的时区调整?
解决方案
一、直接提取年月日数值
1. SQL查询时拆分字段
直接在SQL里把DATE拆成年、月、日三个字段返回,完全规避时区转换:
SELECT EXTRACT(YEAR FROM DATE_COLUMN) AS DATE_YEAR, EXTRACT(MONTH FROM DATE_COLUMN) AS DATE_MONTH, EXTRACT(DAY FROM DATE_COLUMN) AS DATE_DAY FROM YOUR_TABLE
Java代码里直接读取三个数值:
int year = resultSet.getInt("DATE_YEAR"); int month = resultSet.getInt("DATE_MONTH"); int day = resultSet.getInt("DATE_DAY");
2. 用Oracle原生DATE对象读取
如果不想改SQL,可通过Oracle JDBC提供的oracle.sql.DATE类直接获取原始日期信息:
import oracle.sql.DATE; DATE oracleDate = (DATE) resultSet.getObject("DATE_COLUMN"); // 注意转换逻辑:getYear()返回的是相对于1900的差值,getMonth()返回0-11 int year = oracleDate.getYear() + 1900; int month = oracleDate.getMonth() + 1; int day = oracleDate.getDate(); // 直接返回1-31的日
这种方式不会触发任何时区调整,读取的就是数据库里存储的原始年月日。
二、获取对应UTC 0点的时间戳
1. 配置JDBC连接时区
在JDBC连接URL中指定时区为UTC,驱动会把数据库DATE当作UTC时间处理:
jdbc:oracle:thin:@//your-db-host:1521/your-db-service?oracle.jdbc.timezoneAsRegion=false&userTimezone=UTC
或者在加载JDBC驱动前设置系统属性:
System.setProperty("oracle.jdbc.timezoneAsRegion", "false"); System.setProperty("user.timezone", "UTC");
之后调用resultSet.getDate("DATE_COLUMN")得到的就是对应UTC 0点的时间戳。
2. SQL转换为UTC时间
在查询时把DATE字段转换成UTC时区的时间再返回:
SELECT CAST(SYS_EXTRACT_UTC(CAST(DATE_COLUMN AS TIMESTAMP)) AS DATE) AS UTC_DATE FROM YOUR_TABLE
Java中读取UTC_DATE字段,得到的时间戳就对应目标UTC时间。
内容的提问来源于stack exchange,提问作者potato_programmer
相关产品推荐
相关产品推荐

