当前位置:首页 > 问答 > 正文

说说Oracle数据库那些时间函数到底怎么用,细节和技巧一起聊聊

Oracle官方文档、OCP认证教材、资深DBA经验分享)

聊Oracle的时间函数,得先明白它怎么存时间,Oracle有个叫DATE的类型,它很特别,能把日期和时间一起存,精确到秒,2023-10-27 15:30:22’,还有个更精确的TIMESTAMP,能到小数秒,弄懂这个基础,函数用起来才不会迷糊。

获取当前时间:SYSDATE vs CURRENT_TIMESTAMP

这是最常用的。SYSDATE 返回数据库服务器当前的日期和时间(来源:Oracle SQL基础手册),你直接 SELECT SYSDATE FROM DUAL; 就行,它是个DATE类型。

CURRENT_TIMESTAMP 呢,返回的是TIMESTAMP WITH TIME ZONE类型,带有时区信息(来源:Oracle SQL参考指南),如果你业务涉及跨时区,比如全球化系统,用这个更靠谱。SYSDATE 就是服务器本地时间,不管时区那套。

小技巧: 在需要极高精度计时的时候,比如计算一个操作花了多少毫秒,别用SYSDATE,因为SYSDATE精确到秒,两次调用间隔太短可能结果一样,这时候应该用 SYSTIMESTAMP(它返回TIMESTAMP WITH TIME ZONE,精度更高),或者甚至用 DBMS_UTILITY.GET_TIME 来获取百分之一秒的时间戳。

玩转日期转换:TO_CHAR 和 TO_DATE

这是最容易出乱子的地方,数据库里存的是个内部格式,我们看的时候要转成字符串,存的时候要把字符串转成日期。

TO_DATE 是把字符串变成DATE类型。关键细节在于格式模型(format model)要匹配(来源:常见错误排查案例),比如你有个字符串‘271023’,想变成日期,你得告诉Oracle顺序是‘DDMMYY’还是‘MMDDYY’?写 TO_DATE('271023', 'DDMMYY') 就是27号10月,写 TO_DATE('271023', 'MMDDYY') 就是10号27月(这显然错了),不匹配?ORA-01843错误立马就来。

TO_CHAR 正好相反,把DATE或TIMESTAMP转成好看的字串,这里有大把技巧。

  • TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') 得到 ‘2023-10-27 15:30:22’,注意!为什么用HH24?因为HH是12小时制,下午3点会显示成03,除非你加AM/PM,很容易混淆。强烈建议24小时制,这是无数人踩坑后的经验。
  • 想取星期几?TO_CHAR(SYSDATE, 'DAY') 返回‘星期四’(中文环境),算第几季度?用Q
  • 高级技巧: 处理中文数字日期,比如要输出‘二零二三年’,可以用 TO_CHAR(SYSDATE, 'YYYY', 'NLS_DATE_LANGUAGE = TRADITIONAL CHINESE'),但更简单的是用格式符SPTO_CHAR(SYSDATE, 'YEAR') 默认可能输出‘TWENTY TWENTY-THREE’,你可以尝试结合NLS参数设置让它输出中文,虽然有点麻烦,但知道有这个可能性就行。

日期计算:加减和间隔

日期不能直接加减数字,但Oracle很聪明,它允许你加减数字,单位是天(来源:Oracle PL/SQL编程)。SYSDATE + 1 是明天,SYSDATE - 0.5 是12小时前。

但更规范、功能更强的是用 INTERVAL 关键字(来源:Oracle 9i后引入的新特性)。

  • 加1小时:SYSDATE + INTERVAL '1' HOUR
  • 加1天2小时3分钟:SYSDATE + INTERVAL '1 02:03' DAY TO MINUTE 用INTERVAL的好处是清晰,不容易算错,特别是涉及月、年的时候,因为月和年的天数不固定,用天数加容易出问题。

提取日期部分:EXTRACT 函数

如果你只想从日期里拿出年、月、日这些单独的部分,用EXTRACT最直接(来源:SQL标准函数,Oracle 9i引入)。 SELECT EXTRACT(YEAR FROM SYSDATE) FROM DUAL; 直接返回2023这个数字。 这比用TO_CHAR再转成数字要简洁和高效。

计算两个日期的差距:MONTHS_BETWEEN

这是个非常实用的函数(来源:Oracle特有函数)。MONTHS_BETWEEN(date1, date2) 计算date1和date2之间相差多少个月,结果是小数,比如差一天,可能就是0.03几个月。 重要技巧: 如果你想取整,比如算工龄、账龄,经常用 FLOOR(MONTHS_BETWEEN(date1, date2)) 来取整月数。

找月底:LAST_DAY 和 下个周几:NEXT_DAY

LAST_DAY(sysdate) 直接返回这个月最后一天的日期,做月度报表特别有用。 NEXT_DAY(sysdate, '星期一') 返回下一个星期一的日期,注意第二个参数是依赖你数据库的字符集的,中文环境就要写‘星期一’,英文环境写‘MONDAY’。

最后聊几个容易栽跟头的细节:

  • 隐式转换陷阱: 千万不要依赖Oracle的隐式转换,比如WHERE date_column = '20231027',有时候能跑,换台服务器设置不同就报错。养成习惯,永远用TO_DATE显式转换
  • 时区坑: 如果你的应用是给不同时区的人用,从设计之初就要想好用DATE还是TIMESTAMP WITH TIME ZONE,不然后期改起来非常痛苦。
  • 默认时间部分: 如果你只插入了日期部分(如TO_DATE('20231027','YYYYMMDD')),没写时间,Oracle默认时间是午夜00:00:00,如果你用BETWEEN做范围查询,漏掉时间部分可能会查不到当天的数据。

Oracle时间函数功能强大,但魔鬼在细节里,多动手试,特别是边界情况,比如2月28号加一个月会怎么样,年底12月加一个月会怎么样,理解了这些,你才算真正会用。

说说Oracle数据库那些时间函数到底怎么用,细节和技巧一起聊聊