简介Oracle 19c TZ41补丁包P35099667面向Windows环境下的Oracle数据库管理员与运维人员专门解决时区数据缺失或陈旧导致的夏令时切换异常、跨时区查询偏差和日志时间错乱等问题适用于需要严格保证全球业务时间准确性的生产环境。整个压缩包仅352KB包含10个文件以6个dat时区规则文件为核心配合2个xml配置清单与2个txt说明文档内容紧凑、结构清晰可直接用于19c数据库的时区库升级。目前已有703人学习下载是Windows平台下进行TZ41补丁维护时较为实用的参考包。借助该压缩包可一次获取补丁所需的核心数据与官方配套说明减少在Oracle支持站点逐项检索的麻烦结合官方文档能规范完成时区库更新避免因手工配置疏漏引发的时间计算错误从而提升数据库在跨时区业务场景下的稳定性和合规性。1. 这个 zip 不是普通安装包oracle19c TZ41 补丁 p35099667-190000-MSWIN-x86-64.zip 到底该给谁用跑在 Windows Server 上的 Oracle 19c某个跨境订单系统突然出现“订单时间差一小时”的投诉。查业务、查应用、查网络都正常最后定位到数据库时区规则过期——这就是你需要在 oracle19c 上补一个 TZ41 补丁的典型场景。p35099667-190000-MSWIN-x86-64.zip 是 Oracle 官方面向 Microsoft Windows x86-64 平台的 19c 时区版本 41TZ41补丁包作用不是修 Bug而是把数据库内置的时区规则手册整体换新版让 SYSTIMESTAMP、TSTZ 字段在遇到各国各地区调整夏令时规则后依然算出正确时间。它适合正在维护 19c 单实例或 RAC、需要做数据迁移或跨版本导数的 DBA 和数据工程师。网上那些 oracle19c 安装包、安装教程里的常规步骤都不包含这一步这是一次独立的补丁作业。2. 装前三个前置条件先查时区版本、再对 RU 版本、最后做备份2.1 用 SQL*Plus 的 show 命令先确认当前 TZ 版本动手之前必须搞清楚数据库现在的时区版本号。Oracle 19c 在不同小版本里自带的时区版本不一样19.3 初始是 26后续 RU 会逐步推到 31、32、33 甚至更高。如果你当前版本已经等于 41那这个补丁对你没有意义如果低于 41才需要往下走。用 sqlplus 以 SYSDBA 登录后第一件事件不是打补丁而是查 V$TIMEZONE_FILE 视图。sqlplus / as sysdba SQL SELECT * FROM V$TIMEZONE_FILE; SQL SHOW PARAMETER db_timezone; SQL SELECT DBTIMEZONE FROM DUAL;第一句返回的就是当前数据库使用的时区文件版本VERSION 列显示的是数字版本号。第二第三句确认数据库的默认时区设置是“本地时区”还是某个绝对偏移量。这里有一个在实际项目中容易忽略的点V$TIMEZONE_FILE 返回的版本号代表“数据库当前能解析的时区规则上限”它不代表你的每条 TSTZ 数据都存了新规则。数据自身的时区信息是写入时就固化了的升级时区版本只是让数据库“认识更多新规则”旧数据仍按写入时的规则解释。如果 VERSION 显示 33 或更低而你的业务覆盖的国家在近两年调整过夏令时或标准时那这单业务就有真实的时区风险。这种场景在跨境支付、国际物流、全球调度系统里特别常见我经手的几个项目最后都补了 TZ 补丁。2.2 TZ41 不是独立补丁RU 依赖和 OJVM 版本要一起对时区补丁在 MOS 上不是孤立的TZ41 一般跟随某个季度 Release UpdateRU一起发布。包名里的 190000 表示它面向 19.0.0.0.0 基线但你的环境很可能已经打到了 19.20 或更高的 RU 版本这时需要确认补丁 README 里的 prerequisite 是否有最低 RU 要求。常见做法是先在测试环境模拟一次“当前 RU TZ41”的组合然后看两样东西OPatch 版本是否满足补丁脚本要求低于要求时补丁应用器会直接退出数据库是否装了 OJVM 组件。OJVM 有自己的 Java 时区数据文件如果只更新数据库主时区文件而不更新 OJVM用 JDBC Thin 驱动或数据库内 Java 存储过程访问时间字段时可能出现时区版本不一致。# 查看当前 OPatch 版本 cd %ORACLE_HOME%\OPatch opatch version # 查看数据库已安装的 RU 补丁 opatch lsinventory -bugs_fixed | findstr /i 35在 Windows 下这些命令要在管理员 CMD 里执行不要用普通用户权限。opatch lsinventory 输出的补丁号清单里能看到近期季度 RU 的补丁号把它记下来。如果你发现当前 RU 比 TZ41 配套的 RU 老很多我的建议是先把 RU 升到配套版本再打 TZ41不要反着来。反过来操作虽然有时也能跑通但数据字典里一些和时间相关的内部元数据可能停留在旧状态后续跑 DBMS_STATS 或跨版本导出时会有隐患。2.3 全库备份与元数据导出这条不能省时区升级本质上是改写数据库的时区数据字典和全部 TSTZ 列的内部表示一旦中途中断或脚本报错库可能处于“时区版本已改、数据未转换完成”的中间态这时候后悔药只有备份。冷备在 Windows 上对于单实例是最稳妥的但生产环境通常不允许停机窗口太长所以更实际的是 RMAN 全量备份加归档日志。-- RMAN 全备示例 RMAN BACKUP DATABASE PLUS ARCHIVELOG FORMAT D:\backup\TZ41_%U TAG PRE_TZ41; RMAN BACKUP CURRENT CONTROLFILE FORMAT D:\backup\ctl_%U;FORAMT 参数里的 %U 是 Oracle 自动生成唯一文件名避免覆盖TAG 用来标记这次备份的用途后面恢复时可以直接通过 TAG 找到它。PLUS ARCHIVELOG 会把当前所有归档日志一起备份确保一致性。备份完成后还有一个很多人会忽略的元数据检查如果这台库以后要参与 Data Pump 导出导入或者要做 PDB 迁移目标库的时区版本必须不低于源库否则会出现 ORA-39405。所以提前把当前版本的 TZ 版本号记录到变更单里比事后想起来再回去查要省事得多。另外在 Windows 平台上备份路径不要带中文和空格RMAN 的 FORMAT 字符串对路径解析比较敏感。我见过因为路径带空格导致备份集在 restore 时找不到文件的情况那次恢复浪费了将近两个小时。3. Windows 上打补丁的全过程TZRDP 更新软件、TZRU 更新数据库3.1 解压补丁包与管理员权限下载回来的 p35099667-190000-MSWIN-x86-64.zip 是一个压缩包不是直接运行的安装程序。先在目标服务器上用管理员身份解压不要双击打开后直接拖文件因为 zip 里包含长路径文件和脚本资源管理器解压有时会截断路径。# 以管理员身份运行 PowerShell Expand-Archive -Path D:\download\p35099667-190000-MSWIN-x86-64.zip -DestinationPath D:\p35099667 Get-ChildItem -Path D:\p35099667 -Recurse | Select-Object FullName解压后你会看到两类内容对应两种用途。一类是 TZRDPTimeZone Rule Data Patch用于更新 ORACLE_HOME 里的时区文件相当于给“时区规则手册”换新版本这影响之后所有新建数据库另一类是 TZRUTimeZone Rule Update用于更新已经存在的数据库实例它会真正改写数据库内部时区数据。在 Windows 上执行 TZRDP 时记得先确认当前终端是管理员权限。Oracle 的补丁脚本会往 ORACLE_HOME 的 system 目录写文件也会碰注册表普通权限下即使不报错也可能出现文件写了但权限不完整后续 SQL*Plus 启动时读不到新文件。:: 进入 TZRDP 目录后按 README 执行对应程序 cd D:\p35099667\TZRDP部分版本在 Windows 上的 TZRDP 是以图形向导方式运行的你需要手动指定 ORACLE_HOME 路径也有的版本提供命令行入口。打开 README 确认一下这个包具体是哪一种。这一步很关键我吃过一次亏在 Linux 上用惯了命令行到 Windows 上想当然去找可执行文件结果它是个图形安装器白折腾了一阵。3.2 已建库执行 TZRUPDB 全开是硬条件ORACLE_HOME 更新完接下来处理已经存在的数据库。TZRU 部分提供的是 SQL 脚本需要在 SQL*Plus 里以 SYSDBA 身份执行。在执行之前先确认所有 PDB 都处于 OPEN 状态。TZRU 会遍历所有容器数据库的时区数据如果某个 PDB 是 MOUNTED脚本执行会中断或跳过留下不一致状态。-- 确认所有 PDB 状态 SELECT name, open_mode FROM v$pdbs; -- 如果有非 READ WRITE 的 PDB先打开 ALTER PLUGGABLE DATABASE ALL OPEN;确保全部 OPEN 后按 README 里 TZRU 目录的说明执行升级脚本。脚本做的事情分成三步把新时区文件注册进数据字典、扫描所有 TSTZ 类型列并应用新规则、最后更新 V$TIMEZONE_FILE 的版本号。执行过程中要盯住脚本输出。最常见的报错是 ORA-01881 或 ORA-01882通常指向环境变量 TZ 与数据库时区不一致或者某个 PDB 存在异常会话占用。简单处理方式是先把 Windows 系统时区设为 UTCSET TZUTC再重新执行。注意这里说的系统时区只是影响会话环境变量不影响数据库存的业务时间。脚本执行完成后正常现象是 SQL*Plus 会话断开重连然后查询 V$TIMEZONE_FILE 能看到 41。如果看到 41 但业务侧依然报时区错误不要急着重复执行脚本先看完第 5 章的排查点再说。重复执行 TZRU 不是幂等的容易把时区数据搞乱。3.3 时区文件是怎么替换的搞清楚黑匣子才能排错TZRU 脚本不是简单地把文件复制到 ORACLE_HOME它要处理的是数据库内部已经存储的历史数据。每条 TIMESTAMP WITH TIME ZONE 列的内部表示包含一个时区 ID这个 ID 指向时区文件里某个规则集。新时区文件 41 可能重新编号了部分时区 ID所以脚本需要把旧 ID 映射到新 ID再重算需要转换的偏移量。这就是为什么升级完以后SELECT * FROM V$TIMEZONE_FILE 看到版本号变了但某些历史数据的显示时间可能依然按旧规则算——因为它们被转换时使用的是“会话当时读到的规则”而不是重新解析字符串。如果你有跨大版本升级或 Data Pump 导入的需求一定在升级完 TZ 后再次 expdp 导出时重新生成数据不要在升级前导出的 dump 文件上做文章。实际项目里我见过一种情况TZRU 跑完版本号已经是 41但应用连上来取 SYSTIMESTAMP 还是差一小时。最后发现是应用服务器的 JDBC 驱动太老客户端自带的时区规则覆盖了服务端返回的偏移量。这种问题不是数据库侧能解决的得把驱动同步升级到支持 TZ41 的版本。4. RAC、CDB/PDB 和注册表多环境下的 TZ41 操作边界4.1 RAC 双节点要按顺序滚动不能两个节点同时动手如果你的环境是 oracle19c RAC不是单实例流程上有一个明显的区别TZRDP 更新 ORACLE_HOME 时必须保证应用连接不受影响所以要按节点滚动执行。常见做法是把节点 2 的实例先停掉在节点 2 上做 ORACLE_HOME 的 TZRDP 更新更新完启动节点 2 实例再把连接切到节点 2停节点 1在节点 1 上做同样操作。# 以 grid 用户或具有 sysasm 权限的用户执行 srvctl stop instance -d orcl -i orcl2 # 在节点 2 本地执行 TZRDP 更新 ORACLE_HOME # 更新完成后启动实例 srvctl start instance -d orcl -i orcl2 # 切换后处理节点 1 srvctl stop instance -d orcl -i orcl1RAC 环境绝对不能两个节点同时跑 TZRU 脚本。因为 TZRU 要更新数据字典里的共享对象两个节点同时操作会出现内部锁竞争甚至死锁严重时可能导致实例崩溃。即使你只想更新其中一个节点TZRU 也会通过内部传播机制影响整个集群所以必须选业务低峰期操作并提前通知应用方连接会短暂中断。还有一点要注意Windows 上的 RAC 和 Linux 上安装步骤差异不小。RAC 安装包里的 ORACLE_HOME 路径在各个节点的本地磁盘上要完全一致TZRDP 也只认注册表里登记的那个路径。如果你当初装 RAC 时节点间路径不一致补丁安装器很可能认不到第二个节点的 HOME。4.2 PDB 必须全部 OPEN 再跑 TZRU这条规则在 19c 里比 12c 更严格19c 的 CDB/PDB 架构下时区版本存在 CDB 级但每个 PDB 可以有自己的时区设置。TZRU 升级时面向前提是“所有 PDB 处于 OPEN 状态”因为脚本需要逐一访问每个 PDB 的系统表来更新时区元数据。有些 DBA 嫌麻烦只把业务 PDB 打开把其他 PDB 留在 MOUNTED让脚本跑完结果到后期发现某个未打开的 PDB 的时区版本还停留在旧版。等到业务迁移到那个 PDB再做跨时区计算出来的结果和主库不一致排查起来很费劲。所以我习惯在打补丁前做一个一次性检查脚本把所有 PDB 的状态、时区版本都列出来留档备查。-- 确认每个 PDB 当前的时区版本 SELECT c.name AS pdb_name, c.open_mode, t.VERSION AS tz_version FROM v$pdbs c LEFT JOIN v$timezone_file t ON 11 ORDER BY c.name;这里 V$TIMEZONE_FILE 在 CDB 根下查询得到的是容器整体的时区版本PDB 自身的时区设置用 DBTIMEZONE 查看。很多资料里说“PDB 的时区版本跟随 CDB”这句话不严谨。CDB 升级后已存在的 PDB 不经过 TZRU 转换它的 TSTZ 数据仍然按旧规则解释所以每一个 PDB 都要在 OPEN 状态下被脚本扫过一遍。4.3 Windows 注册表残留会挡住补丁安装Windows 平台的 Oracle 组件和补丁程序会在注册表里写安装状态。如果你之前卸载过 Oracle 组件但没清理干净TZRDP 安装器读取注册表时会认为对应组件已存在或版本状态异常直接中止安装。最典型的报错是日志里出现“Location of the Oracle Home is not registered”或“Oracle Home does not exist”但明明 ORACLE_HOME 路径是有效的。这类问题在 Windows Server 上尤其频繁因为很多人之前卸载 oracle19c 时只删了目录没有处理注册表。排查注册表残留可以这样做reg query HKLM\SOFTWARE\ORACLE /s /f KEY_ | findstr /i ORACLE_HOME reg query HKLM\SOFTWARE\WOW6432Node\ORACLE /s /f KEY_ | findstr /i ORACLE_HOME如果你看到多余的 ORACLE_HOME 指向一个已经不存在或者根本不相关的目录需要手动删除对应的 KEY 注册表键。删之前建议先导出备份用 reg export 导出那个键再删除。这个操作属于注册表级操作动手前确认影响范围不要在不确定的情况下乱删。我在一个客户现场遇到过补丁反复装不上查了日志发现注册表里有两个 ORACLE_HOME_NAME一个指向 C 盘另一个指向 D 盘而 D 盘那个目录早就被删掉了。卸载时卸载程序没有清注册表导致补丁安装器以为还有一个 Oracle 环境存在。清理后补丁一次通过。5. 避坑TZ41 升级常见的五个翻车点与排查5.1 ORA-39405源库时区版本高于目标库现象用 Data Pump 从 A 库导入 B 库报错 ORA-39405提示源库时区版本大于目标库impdp 无法继续。原因A 库已经打了 TZ41B 库还在旧版本impdp 不接受目标库时区版本低于源库的数据。解决这个报错在打补丁前最常出现。正确顺序是先给目标库打 TZ41 补丁再执行导入。如果目标库也打了补丁仍然报错检查目标库的 V$TIMEZONE_FILE 是否真的返回 41而不是只看补丁是否安装成功。5.2 TZRU 跑完版本没变脚本实际没有生效现象TZRU 脚本执行过程中没有明显报错但重查 V$TIMEZONE_FILE 还是旧版本。原因最常见是你在 SQL*Plus 里执行脚本时连接的会话不是 CDB 根而是某个 PDB或者脚本在某个 PDB 上中断后表面显示成功但事务被回滚。解决确认连接方式为sqlplus / as sysdba并且SELECT CON_ID FROM V$SESSION WHERE SID USERENV(SID)返回 0 或 1。若在 PDB 里执行先 ALTER SESSION SET CONTAINERCDB$ROOT再重新跑脚本。另外检查脚本输出末尾是否有“ERROR”字样不能只看前面几行成功日志。5.3 ORA-01882时区版本不匹配导致时间越界现象TZRU 升级后某条 SQL 查询报 ORA-01882“timezone region cannot be found”或“timezone region ID is invalid”。原因DBA 改过数据库或会话的时区区域设置指定了时区文件里不存在的区域 ID或者应用连接池里存在升级前创建的旧会话。解决检查环境变量 TZ 是否被设置为一个奇怪的值比如某个城市缩写。Windows 环境下推荐在 TZRU 升级期间把系统时区临时改为 UTC升级完成后恢复。业务侧需要重启连接池让所有会话重新读取新的时区数据。5.4 升级后 JDBC 程序连接报时区版本不兼容现象数据库已确认 TZ 版本为 41Java 应用启动时报错类似“ORA-00600 或 timezone file version mismatch”。原因客户端 JDBC 驱动ojdbc内置的时区版本太旧和服务器端 41 不兼容。JDBC 驱动和数据库之间会协商时区版本版本差距过大会直接拒绝连接。解决把应用的 ojdbc.jar 升级到支持 TZ41 的版本通常随 19c 最新 RU 一起发布的 JDBC 版本可以匹配。升级后重启应用测试。如果应用是 WebLogic 或 Tomcat还要确认 JVM 系统属性-Duser.timezone没有被硬编码成某个固定时区。5.5 卸载补丁后注册表残留导致重复安装失败现象第一次 TZ41 补丁打完因为某种原因回滚卸载再重装时报错“Product already installed”但实际时区版本还是旧的。原因卸载程序删除了 ORACLE_HOME 下的文件但注册表条目没有同步清理重装时安装器读到残留状态。解决按照 4.3 节的方法清理 HKLM\SOFTWARE\ORACLE 和 HKLM\SOFTWARE\WOW6432Node\ORACLE 下与本库无关的 ORACLE_HOME 键清理后再重装。清理前先确认目标键确实指向不存在的目录避免误删正在使用的环境。6. 验证 TZ41 生效的两个实测动作和一个长期习惯验证的第一步不是看业务时间对不对而是确认数据库层面的版本号已经更新。重新连接 SQL*Plus执行SELECT * FROM V$TIMEZONE_FILE;VERSION 列必须为 41。这一步看起来简单但实践中很多人都忘了在重连后验证导致后面排查走了弯路。第二步是选择一个真实受影响的时区做前后对比。TZ41 的 README 里通常会列出本次新纳入的时区规则变化点你可以挑一个业务相关的时区做一次计算验证。比如把某个日期时间字符串转成带时区的 TIMESTAMP再用 FROM_TZ 和 AT TIME ZONE 做转换。-- 以某个受影响的时区为例示例写法实际时区区域名以 README 为准 SELECT FROM_TZ(CAST(TO_DATE(2025-03-30 01:30:00, YYYY-MM-DD HH24:MI:SS) AS TIMESTAMP), Europe/Paris) AT TIME ZONE UTC AS utc_time FROM DUAL;如果 README 里列出的规则变化日期在这条 SQL 前后结果偏移量不同说明新规则已经生效。这里要强调的是验证用的时区区域名必须精确匹配 V$TIMEZONE_NAMES 视图里的名字不能简写或使用城市名的中文翻译。做完这两步后我还有一个长期习惯把 TZ41 升级记录写进变更表连同 RU 补丁号、OJVM 版本、JDBC 驱动版本一起记录。下一轮季度补丁发布时先看时区版本是否变化再决定要不要再打新的 TZ 补丁。时区补丁这件事最怕的不是不会打而是打了以后没人记得打了什么半年后出了问题无从查起。从那以后我每次遇到跨版本导数或国际业务迁移都会先确认源库和目标库的时区版本差把 TZ 补丁纳入 RU 升级的标准动作不再等业务反馈时间错了才回头补。这套流程跑通以后希望帮到你。本文还有配套的精品资源点击获取