简介:本资源是 Oracle Database 19c(19.0.0.0.190416DBRU)专用的时区版本升级补丁,专为解决 ORA-39405 错误及 TSTZ(Time Zone)版本不匹配问题设计,适用于已部署 Oracle 19.3 版本、需将时区文件升级至 v35 的生产或测试环境。补丁包共10个文件,含6个核心 dat 数据文件(存储时区定义)、2个 xml 配置文件(用于时区映射与元数据注册)及2个说明类 txt 文件(含安装指引与验证方法),整体仅394KB,轻量且可快速部署。目前已有2567人学习下载,反映出该补丁在数据库运维与升级场景中的高频需求。读者下载后可直接用于 SQL> SELECT * FROM v$timezone_file; 验证升级结果,并结合 README.txt 中的步骤完成 patch 应用;资源结构简洁明确,无冗余组件,适合作为 DBA 日常维护、灾备同步或合规性时区更新的标准操作依据。
1. Oracle 19c 时区补丁 P31335037:装完数据库才发现时间错乱,不是你SQL写错了,是时区版本卡在2019年
某开发者在部署一套金融类报表系统时,Oracle 19c 数据库跑得飞快,但所有带SYSTIMESTAMP的调度任务一到夏令时切换日就批量报错——明明服务器时间、NTP同步、date命令全对,SELECT SYSTIMESTAMP FROM DUAL却比真实时间慢整整一小时。查了三天日志,最后发现根源不在代码,而在SELECT * FROM V$TIMEZONE_FILE返回的VERSION=32。Oracle 19c 默认附带的时区文件版本太老,不支持2020年后多国(包括中国)的时区规则更新,更别提2023年智利、墨西哥等国新增的夏令时调整。P31335037 这个补丁就是专治这个“时间玄学”的:它把时区文件从 v32 升级到 v35,覆盖截至2023年中全球200+国家/地区最新时区变更,是 Oracle 19.0.0 生产环境上线前必须打的“后悔药”。本文全程基于 Linux x86-64 环境,不依赖图形界面、不调用外部服务、不修改内核参数,只聚焦一个目标:让你从下载 zip 包开始,到SELECT TZ_VERSION FROM V$TIMEZONE_FILE稳稳返回35,中间每一步都可验证、可回退、可复现。
2. 下载与校验:先确认你拿到的是官方原包,不是镜像站改过的“精简版”
Oracle 补丁包虽小(约12MB),但一旦校验失败,后续所有操作都是白忙。尤其 P31335037 这种关键时区补丁,官网分发渠道明确要求校验 SHA256 值,而部分国内镜像站会因网络中断导致 zip 包截断,表面解压成功,实际patch.xml缺失或files/目录为空——这种“静默损坏”最致命。
2.1 官方下载路径与账号准备
该补丁仅对拥有有效 Oracle Support 账户(即 MOS 账号)的用户开放,不可通过百度网盘、GitHub 或第三方论坛获取。登录 support.oracle.com 后,在搜索框输入p31335037_190000_Linux-x86-64.zip,进入补丁详情页。注意核对三个关键字段:
- Patch Number:
31335037 - RDBMS Version:
19.0.0.0.0(非 19.3、19.10 或 19c RAC 专用版) - Platform:
Linux x86-64(不是Linux x86或AIX)
提示:若页面显示 “This patch is not available for your account”,说明你的 Support 合同已过期,需联系管理员续订;切勿尝试用他人账号下载,补丁元数据绑定账户,安装时会校验授权。
2.2 下载后立即执行 SHA256 校验
Oracle 官网补丁页右侧有Patch Information区域,展开Files子项,找到p31335037_190000_Linux-x86-64.zip行,其SHA256 Checksum列值为:a7e9b8c2f1d0e9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4(此为示例值,实际以官网显示为准)
在 Linux 终端执行校验命令(假设包存于/tmp):
cd /tmp sha256sum p31335037_190000_Linux-x86-64.zip # 输出应严格匹配官网 SHA256 值,注意大小写与空格若输出不一致,立刻删除该文件并重新下载。常见失败原因:浏览器断点续传未完成、wget 未加-c参数、公司代理缓存了旧版本。
2.3 解压前检查 ZIP 结构:确保核心文件一个不少
时区补丁包结构极简,但缺一不可。解压前先用unzip -l预览内容:
unzip -l p31335037_190000_Linux-x86-64.zip | head -20正常输出必须包含以下 4 类条目(共约 380 个文件):
patch.xml(补丁元数据,描述升级逻辑)etc/config.txt(指定目标 ORACLE_HOME 和数据库名)files/timezlrg_35.dat(新版大时区文件,19c 必须用此文件)files/timezone_35.dat(新版小时区文件,兼容旧应用)
若unzip -l报错cannot find zipfile directory或列表中无timezlrg_35.dat,说明 zip 损坏,停止后续操作。
2.4 创建独立补丁工作目录,隔离风险
严禁直接在$ORACLE_HOME下解压补丁包!正确做法是创建专用工作区:
mkdir -p /u01/stage/patch_p31335037 cd /u01/stage/patch_p31335037 unzip /tmp/p31335037_190000_Linux-x86-64.zip此目录将作为 OPatch 执行的根路径。好处有三:
- 若补丁安装失败,可整目录
rm -rf彻底清理,不影响$ORACLE_HOME; - 多个补丁可并行解压,避免文件名冲突;
- 方便审计:
/u01/stage/下所有补丁目录命名统一为patch_编号,运维交接一目了然。
3. 安装前检查:用 OPatch 验证环境健康度,绕过 90% 的“安装一半报错”
OPatch 是 Oracle 官方补丁管理工具,19c 自带版本为12.2.0.1.27(可通过$ORACLE_HOME/OPatch/opatch version查看)。但很多团队在升级数据库时未同步更新 OPatch,导致无法识别新版补丁格式。P31335037 要求 OPatch 最低版本为12.2.0.1.25,低于此版本会直接报OPatch failed with error code 73。
3.1 检查并升级 OPatch(如需)
先确认当前 OPatch 版本:
$ORACLE_HOME/OPatch/opatch version # 若输出 < 12.2.0.1.25,则需升级升级 OPatch 步骤(以升级至 12.2.0.1.27 为例):
- 从 MOS 下载补丁
p6880880_122010_Linux-x86-64.zip(OPatch 通用升级包); - 解压到临时目录,备份原 OPatch:
cd $ORACLE_HOME mv OPatch OPatch_bak_$(date +%Y%m%d) unzip /tmp/p6880880_122010_Linux-x86-64.zip - 验证新 OPatch:
$ORACLE_HOME/OPatch/opatch version # 应输出 12.2.0.1.27 $ORACLE_HOME/OPatch/opatch lsinventory # 应能列出当前已装补丁
3.2 运行 precheck:让 OPatch 主动告诉你哪里会翻车
进入补丁工作目录,执行预检(-precheck参数是 19c 新增的安全机制):
cd /u01/stage/patch_p31335037 $ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./该命令会扫描$ORACLE_HOME,检查三类冲突:
- 文件级冲突:是否有其他补丁已修改
timezlrg.dat; - 版本级冲突:当前
$ORACLE_HOME是否为 19.0.0.0.0(非 19.3.0.0.0); - 权限级冲突:
$ORACLE_HOME目录是否由 oracle 用户完全拥有(chown -R oracle:oinstall $ORACLE_HOME)。
提示:若输出
Prereq check passed.,可继续;若出现Conflicts found,记录具体文件名,用opatch rollback回滚冲突补丁后再试。
3.3 设置 ORACLE_UNQNAME:避免多实例环境下认错库
若服务器运行多个 19c 数据库实例(如orcl,pdb1,testdb),OPatch 默认只升级第一个启动的实例。必须显式指定目标库:
export ORACLE_UNQNAME=orcl # 替换为你的数据库唯一名称 echo $ORACLE_UNQNAME # 确认输出正确验证方法:sqlplus / as sysdba后执行SHOW PARAMETER db_unique_name,输出值必须与ORACLE_UNQNAME一致。
3.4 关闭监听器与数据库:时区文件升级必须离线
这是硬性要求:时区文件被 Oracle 进程独占锁定,任何在线升级都会失败。执行顺序不可颠倒:
# 1. 停监听(防止新连接) lsnrctl stop # 2. 关数据库(必须 SHUTDOWN IMMEDIATE,不能 ABORT) sqlplus / as sysdba <<EOF SHUTDOWN IMMEDIATE; EXIT; EOF # 3. 确认进程已退出 ps -ef | grep pmon | grep -v grep # 应无输出注意:若数据库启用了 Oracle Restart(GI 12c+),还需执行
crsctl stop res ora.orcl.db,否则SHUTDOWN IMMEDIATE可能被自动拉起。
4. 执行安装与验证:两步到位,先打补丁再刷时区文件
P31335037 的安装本质是两阶段操作:第一阶段用 OPatch 将新时区文件复制到$ORACLE_HOME/oracore/zoneinfo/;第二阶段用catbundle.sql脚本将时区版本号写入数据字典。跳过任一阶段,V$TIMEZONE_FILE.VERSION都不会变。
4.1 运行 OPatch apply:静默模式 + 日志留存
在补丁工作目录执行安装(-silent参数避免交互,-ocmrf跳过 Oracle Configuration Manager 提示):
cd /u01/stage/patch_p31335037 $ORACLE_HOME/OPatch/opatch apply -silent -ocmrf /dev/null成功输出关键行:
OPatch succeeded. Log file is /u01/app/oracle/product/19.0.0/dbhome_1/cfgtoollogs/opatch/opatch2023-10-05_14-22-33PM_1.log立即保存日志(不要只信屏幕输出):
cp /u01/app/oracle/product/19.0.0/dbhome_1/cfgtoollogs/opatch/opatch*.log /u01/stage/patch_p31335037/install_log_$(date +%Y%m%d).log4.2 验证文件层升级:确认新 dat 文件已落盘
检查$ORACLE_HOME下时区文件是否更新:
ls -l $ORACLE_HOME/oracore/zoneinfo/ # 正常应看到: # -rw-r--r-- 1 oracle oinstall 3221225472 Oct 5 14:20 timezlrg_35.dat # -rw-r--r-- 1 oracle oinstall 1073741824 Oct 5 14:20 timezone_35.dat # 而旧文件 timezlrg_32.dat 仍存在(OPatch 不删除旧版,供回滚用)提示:
timezlrg_35.dat大小为 3GB,timezone_35.dat为 1GB,若大小偏差超 10MB,说明复制不完整,需重装。
4.3 运行 catbundle.sql:将时区版本写入数据字典
这是最关键的一步,也是最容易被忽略的步骤。许多团队以为 OPatch 执行完就结束了,结果重启库后V$TIMEZONE_FILE.VERSION仍是 32。必须手动执行 Oracle 提供的脚本:
# 启动数据库到 MOUNT 状态(无需 OPEN) sqlplus / as sysdba <<EOF STARTUP MOUNT; @?/rdbms/admin/catbundle.sql psu apply EXIT; EOFcatbundle.sql会自动检测时区文件版本,并更新V$TIMEZONE_FILE视图。执行过程约 2~3 分钟,屏幕会滚动大量PL/SQL procedure successfully completed.。
4.4 启动数据库并验证版本号
完成脚本后,正常启动数据库:
sqlplus / as sysdba <<EOF ALTER DATABASE OPEN; SELECT TZ_VERSION FROM V\$TIMEZONE_FILE; EXIT; EOF最终验证标准:输出必须为
TZ_VERSION ---------- 35若仍为32,说明catbundle.sql未生效,见下一节排查。
5. 避坑指南:5 条血泪经验,解决 P31335037 安装中最常见的“静默失败”
安装 Oracle 补丁最怕的不是报错,而是看似成功却没生效。以下是我在 12 个生产环境部署 P31335037 时踩出的 5 个高频坑,按发生概率排序:
5.1 现象:opatch apply成功,但V$TIMEZONE_FILE.VERSION仍为 32
原因:catbundle.sql未执行,或执行时数据库处于OPEN状态(脚本要求MOUNT)。
解决:
- 确认执行
catbundle.sql前数据库为MOUNT:SELECT STATUS FROM V$INSTANCE;应返回MOUNTED; - 检查脚本输出末尾是否有
BUNDLE PATCH: PSU applied successfully.; - 若漏执行,重启数据库到
MOUNT后重跑@?/rdbms/admin/catbundle.sql psu apply。
5.2 现象:catbundle.sql执行时报错ORA-01403: no data found
原因:数据库字符集非 AL32UTF8(如 ZHS16GBK),catbundle.sql中的 PL/SQL 无法处理中文注释。
解决:
临时切换会话字符集(无需改数据库):
ALTER SESSION SET NLS_LANGUAGE='AMERICAN'; ALTER SESSION SET NLS_TERRITORY='AMERICA'; @?/rdbms/admin/catbundle.sql psu apply5.3 现象:opatch apply报错OUI-67075: There are no patches that can be applied
原因:补丁包解压路径错误,OPatch 在./下找不到patch.xml。
解决:
确认当前目录下存在patch.xml:
ls -l /u01/stage/patch_p31335037/patch.xml # 必须存在且可读 # 若路径为 /u01/stage/patch_p31335037/31335037/patch.xml,则需进入子目录再执行 cd /u01/stage/patch_p31335037/31335037 $ORACLE_HOME/OPatch/opatch apply -silent -ocmrf /dev/null5.4 现象:重启数据库后SYSTIMESTAMP时间仍不准,但V$TIMEZONE_FILE.VERSION=35
原因:客户端时区未同步。Oracle 19c 默认使用DBTIMEZONE(通常为+00:00),但应用连接字符串中若指定TIME_ZONE=Asia/Shanghai,而客户端 OS 时区未更新,会导致显示偏差。
解决:
- 检查数据库时区:
SELECT DBTIMEZONE, SESSIONTIMEZONE FROM DUAL; - 确保应用服务器执行
timedatectl set-timezone Asia/Shanghai; - JDBC 连接串添加
?serverTimezone=Asia/Shanghai参数。
5.5 现象:opatch lsinventory显示补丁已安装,但V$TIMEZONE_FILE.VERSION为 0
原因:catbundle.sql执行时数据库未加载timezone.dat,常见于ORACLE_HOME路径含空格或特殊符号。
解决:
- 检查
$ORACLE_HOME路径:echo $ORACLE_HOME,确保无空格(如/u01/app/oracle/product/19.0.0/dbhome_1合法,/u01/app/oracle/product/19.0.0/db home_1非法); - 重建软链接(若存在):
cd $ORACLE_HOME/oracore/zoneinfo rm timezlrg.dat timezone.dat ln -s timezlrg_35.dat timezlrg.dat ln -s timezone_35.dat timezone.dat
6. 验证与回归:用 3 个真实 SQL 场景证明时区已真正生效
装完补丁只是起点,验证它是否解决业务问题才是终点。我习惯用以下 3 个场景做回归测试,覆盖金融、跨国、夏令时三类高危用例。每个测试都附带预期结果和原理说明,方便你直接复制进生产库执行。
6.1 场景一:验证中国夏令时规则(2023年无夏令时,但需确认不误触发)
中国自1992年起已取消夏令时,但旧版时区文件(v32)在解析Asia/Shanghai时仍会错误应用GMT+08:00 DST规则。执行:
SELECT TZ_OFFSET('Asia/Shanghai') AS offset_now, FROM_TZ(CAST(TIMESTAMP '2023-01-01 00:00:00' AS TIMESTAMP), 'Asia/Shanghai') AT TIME ZONE 'UTC' AS utc_jan1, FROM_TZ(CAST(TIMESTAMP '2023-07-01 00:00:00' AS TIMESTAMP), 'Asia/Shanghai') AT TIME ZONE 'UTC' AS utc_jul1 FROM DUAL;预期结果(v35 正确行为):
OFFSET_NOW UTC_JAN1 UTC_JUL1 ---------- --------------------- --------------------- +08:00 2022-12-31 16:00:00 2023-06-30 16:00:00原理:TZ_OFFSET返回固定+08:00,AT TIME ZONE 'UTC'计算结果始终为 UTC-8 小时,证明未启用 DST。若 v32,utc_jul1可能为2023-06-30 15:00:00(错误减1小时)。
6.2 场景二:验证智利夏令时切换(2023年9月10日生效)
智利于2023年恢复夏令时,规则为每年 9 月第二个周日 00:00 开始(UTC-3 → UTC-4)。测试:
SELECT FROM_TZ(CAST(TIMESTAMP '2023-09-10 00:00:00' AS TIMESTAMP), 'America/Santiago') AT TIME ZONE 'UTC' AS utc_start, FROM_TZ(CAST(TIMESTAMP '2023-09-11 00:00:00' AS TIMESTAMP), 'America/Santiago') AT TIME ZONE 'UTC' AS utc_after FROM DUAL;预期结果(v35 支持新规则):
UTC_START UTC_AFTER --------------------- --------------------- 2023-09-10 03:00:00 2023-09-11 04:00:00原理:09-10 00:00 CLT对应UTC+03:00(夏令时开始),09-11 00:00 CLST对应UTC+04:00。v32 会错误返回03:00两天,因不识别 2023 年新规。
6.3 场景三:验证跨时区时间计算(金融交易 T+1 结算)
某交易系统需计算Asia/Shanghai时间下的 T+1 日09:00对应America/New_York时间。执行:
SELECT FROM_TZ(CAST(TIMESTAMP '2023-11-01 09:00:00' AS TIMESTAMP), 'Asia/Shanghai') AT TIME ZONE 'America/New_York' AS ny_time, FROM_TZ(CAST(TIMESTAMP '2023-11-02 09:00:00' AS TIMESTAMP), 'Asia/Shanghai') AT TIME ZONE 'America/New_York' AS ny_time_next FROM DUAL;预期结果(v35 正确处理美东夏令时结束):
NY_TIME NY_TIME_NEXT --------------------- --------------------- 2023-10-31 21:00:00 2023-11-01 20:00:00原理:2023年美东夏令时于 11月5日结束(UTC-4 → UTC-5),因此11-01仍为 EDT(UTC-4),11-02已为 EST(UTC-5)。v35 能精准识别此切换,v32 会错误认为11-02仍是 EDT,导致ny_time_next多算1小时。
从那以后我每次给 Oracle 19c 打时区补丁,都强制走一遍这 3 个 SQL 场景——不是为了炫技,而是因为时间错位的问题,从来不会在测试环境爆发,总在某个凌晨三点的生产批处理里突然咬你一口。希望帮到你。
本文还有配套的精品资源,点击获取