searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Oracle中TO_DATE用法

2026-06-02 17:46:39
0
0

一、TO_DATE函数到底是什么?

简单来说,TO_DATE函数的核心使命只有一个:将字符串转换为Oracle的DATE数据类型。

Oracle内部存储DATE数据时,使用的是一种内部格式,这意味着当你拿到一个字符串形式的日期,比如 '2024-12-11' 或者 'March 17, 2023',你必须通过TO_DATE函数将其转换为DATE类型,才能正确地存储到DATE列中,或者进行日期运算。

1.1 基本语法

sql
TO_DATE(string, format_mask, [nls_language])
参数 说明 是否必填
string 要转换的日期字符串 ✅ 必填
format_mask 指定字符串的日期格式 ✅ 必填
nls_language 可选,指定语言环境 ❌ 可选

重点来了:format_mask参数是整个TO_DATE函数的灵魂。 它告诉Oracle,你给的这个字符串到底长什么样。如果format_mask写错了,轻则返回NULL,重则直接报错。


二、format_mask格式掩码大全

这是本文最核心的部分,我把所有常用的格式掩码整理成表格,建议收藏。

2.1 年份相关

格式符 含义 示例 结果
YYYY 四位年份 2024 2024
YYY 三位年份 024 024
YY 两位年份 24 24
Y 一位年份 4 4
RRRR 两位年份转四位(00-49→20xx,50-99→19xx) 50 1950
IYYY ISO标准四位年份 2024 2024

特别注意RRRR的妙用: 当你只有两位年份时,使用RRRR可以智能判断世纪。比如输入'50',返回1950;输入'24',返回2024。这在处理老旧系统数据时非常实用。

2.2 月份相关

格式符 含义 示例 结果
MM 两位数字月份(01-12) 12 12月
MON 三位英文月份缩写 DEC DEC
MONTH 完整月份名称(空格填充至9字符) DECEMBER DECEMBER
RM 罗马数字月份(I-XII) XII XII

踩坑预警: 如果你的字符串里写的是"December"而不是"DEC",那你必须用MONTH而不是MON。这是新手最常犯的错误之一。

2.3 日期相关

格式符 含义 示例 结果
DD 当月第几天(01-31) 15 15日
DDD 当年第几天(001-366) 365 第365天
DY 星期缩写 MON MON
DAY 星期全名(空格填充至9字符) MONDAY MONDAY
D 星期几(1=周日,7=周六) 2 周一

2.4 时间相关(重中之重)

格式符 含义 示例 结果
HH 或 HH12 12小时制小时(01-12) 02 02
HH24 24小时制小时(00-23) 14 14
MI 分钟(00-59) 30 30分
SS 秒(00-59) 45 45秒
FF 十亿分之一秒(纳秒级) 123456789 纳秒
AM / PM 上午/下午标识 PM 下午

🚨 致命错误警告:分钟必须用MI,不能用MM!

这是我见过最多的错误。在Java里我们习惯写mm表示分钟,但在Oracle SQL中,MM是月份!如果你写成:

sql
-- ❌ 错误写法,会报 ORA-01810 格式代码出现两次
SELECT TO_DATE('2024-12-11 14:30:45', 'YYYY-MM-DD HH24:mm:ss') FROM dual;

正确写法是:

sql
-- ✅ 正确写法
SELECT TO_DATE('2024-12-11 14:30:45', 'YYYY-MM-DD HH24:MI:SS') FROM dual;

记住:Oracle里分钟是MI,不是MM!


三、实战案例:从入门到精通

3.1 基础转换——最常见的场景

sql
-- 将 '2024-12-11' 转换为 DATE 类型
SELECT TO_DATE('2024-12-11', 'YYYY-MM-DD') FROM dual;
-- 结果:11-DEC-24(Oracle默认显示格式)

-- 带时间的转换
SELECT TO_DATE('2024-12-11 14:30:45', 'YYYY-MM-DD HH24:MI:SS') FROM dual;
-- 结果:11-DEC-24 下午 02:30:45

3.2 插入数据时使用TO_DATE

sql
-- 假设有一张用户表 users(id, name, joined_date)
INSERT INTO users (id, name, joined_date) 
VALUES (1, '张三', TO_DATE('2024-12-11', 'YYYY-MM-DD'));

-- 带时间的插入
INSERT INTO users (id, name, joined_date) 
VALUES (2, '李四', TO_DATE('2024-12-11 09:30:00', 'YYYY-MM-DD HH24:MI:SS'));
 

3.3 处理不同语言的月份名称

当你的日期字符串中包含非英文月份名称时,需要使用第三个参数nls_language

sql
-- 法语月份 "Mai" = 五月
SELECT TO_DATE('05-Mai-2025', 'DD-Mon-YYYY', 'NLS_DATE_LANGUAGE=FRENCH') FROM dual;
-- 结果:05-MAY-25

-- 中文环境下
SELECT TO_DATE('2024年12月11日', 'YYYY"年"MM"月"DD"日"', 'NLS_DATE_LANGUAGE=SIMPLIFIED CHINESE') FROM dual;

你也可以在会话级别设置语言:

sql
ALTER SESSION SET NLS_DATE_LANGUAGE = 'AMERICAN';
SELECT TO_CHAR(TO_DATE('2002-08-26', 'YYYY-MM-DD'), 'DAY') FROM dual;
-- 结果:MONDAY(而不是中文的"星期一")

3.4 求某天是星期几

sql
-- 中文环境
SELECT TO_CHAR(TO_DATE('2024-12-11', 'YYYY-MM-DD'), 'DAY', 'NLS_DATE_LANGUAGE=SIMPLIFIED CHINESE') FROM dual;
-- 结果:星期三

-- 英文环境
SELECT TO_CHAR(TO_DATE('2024-12-11', 'YYYY-MM-DD'), 'DAY', 'NLS_DATE_LANGUAGE=AMERICAN') FROM dual;
-- 结果:WEDNESDAY

3.5 计算两个日期之间的天数

sql
-- 当前日期减去指定日期
SELECT FLOOR(SYSDATE - TO_DATE('2024-01-01', 'YYYY-MM-DD')) AS days_diff FROM dual;

-- 两个指定日期之间的天数
SELECT TO_DATE('2024-12-31', 'YYYY-MM-DD') - TO_DATE('2024-01-01', 'YYYY-MM-DD') AS days_diff FROM dual;
-- 结果:365

3.6 计算月份差

sql
-- 使用 MONTHS_BETWEEN 函数
SELECT MONTHS_BETWEEN(TO_DATE('2024-12-31', 'YYYY-MM-DD'), 
                      TO_DATE('2024-01-01', 'YYYY-MM-DD')) AS months_diff 
FROM dual;
-- 结果:12

-- 非整月的情况
SELECT MONTHS_BETWEEN(TO_DATE('2024-02-01', 'YYYY-MM-DD'), 
                      TO_DATE('2024-01-01', 'YYYY-MM-DD')) AS months_diff 
FROM dual;
-- 结果:1.03225806451613(约1.03个月)

3.7 查询某月内排除周末的天数

这是一个非常实用的业务场景——计算工作日天数:

sql
SELECT COUNT(*) AS workdays
FROM (
    SELECT ROWNUM - 1 AS rnum
    FROM all_objects
    WHERE ROWNUM <= TO_DATE('2024-02-28', 'YYYY-MM-DD') - TO_DATE('2024-02-01', 'YYYY-MM-DD') + 1
)
WHERE TO_CHAR(TO_DATE('2024-02-01', 'YYYY-MM-DD') + rnum - 1, 'D') NOT IN ('1', '7');
-- 结果:20(2024年2月1日到28日之间,排除周六周日的工作日天数)

3.8 处理NULL值

sql
-- 查询时需要用 TO_DATE(NULL) 而不是 NULL
SELECT id, active_date FROM table1
UNION
SELECT 1, TO_DATE(NULL) FROM dual;

如果直接写NULL,Oracle可能会因为类型不匹配而报错。


四、TO_DATE与TO_CHAR的黄金搭档

在实际开发中,TO_DATE和TO_CHAR是一对形影不离的好搭档。一个负责"字符→日期",一个负责"日期→字符"。

操作 函数 示例
字符串转日期 TO_DATE TO_DATE('2024-12-11', 'YYYY-MM-DD')
日期转字符串 TO_CHAR TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS')
提取年份 TO_CHAR TO_CHAR(SYSDATE, 'YYYY')
提取月份 TO_CHAR TO_CHAR(SYSDATE, 'MM')
提取日期 TO_CHAR TO_CHAR(SYSDATE, 'DD')
提取小时 TO_CHAR TO_CHAR(SYSDATE, 'HH24')
提取分钟 TO_CHAR TO_CHAR(SYSDATE, 'MI')
提取秒 TO_CHAR TO_CHAR(SYSDATE, 'SS')

实战:自定义格式化输出

sql
SELECT TO_CHAR(SYSDATE, '"今天是" DD"日" MONTH", "YYYY"年"') AS custom_date FROM dual;
-- 结果:今天是 22日 MAY    , 2026年

SELECT TO_CHAR(SYSDATE, 'YYYY"年"MM"月"DD"日" HH24"时"MI"分"SS"秒"') FROM dual;
-- 结果:2026年05月22日 15时30分45秒
 

五、常见坑点与最佳实践

作为一名老开发,我把这些年踩过的坑全部总结给你:

坑点1:格式掩码大小写不敏感,但必须匹配

Oracle的格式掩码不区分大小写,但你的字符串必须和掩码完全对应。比如掩码写的是MONTH,字符串就必须是完整的月份名;写的是MON,字符串就必须是三字母缩写。

坑点2:默认日期格式的陷阱

如果你不指定format_mask,Oracle会使用NLS_DATE_FORMAT参数的默认值,通常是DD-MON-RR。这意味着:

sql
-- 以下写法依赖默认格式,不推荐!
INSERT INTO x VALUES (99, '31-may-98');

-- 推荐写法,显式指定格式
INSERT INTO x VALUES (99, TO_DATE('1998/05/31:12:00:00AM', 'yyyy/mm/dd:hh:mi:ssam'));
 

最佳实践:永远显式指定format_mask,不要依赖隐式转换!

坑点3:AM/PM与HH12/HH24的搭配

sql
-- ✅ 正确:12小时制 + AM/PM
TO_DATE('02:30:00 PM', 'HH:MI:SS AM')

-- ✅ 正确:24小时制,不需要AM/PM
TO_DATE('14:30:00', 'HH24:MI:SS')

-- ❌ 错误:24小时制配了AM/PM,或者12小时制没配AM/PM
TO_DATE('14:30:00 PM', 'HH24:MI:SS AM')  -- 逻辑矛盾!

坑点4:日期比较时的精度问题

当使用BETWEEN进行日期范围查询时,如果不包含时间部分,边界值可能会被意外排除:

sql
-- 假设 joined_date 是 DATE 类型,包含时间
-- 以下查询可能不包含 12月31日 12:00:00 之后的记录
SELECT * FROM users 
WHERE joined_date BETWEEN TO_DATE('2024-12-01', 'YYYY-MM-DD') 
                      AND TO_DATE('2024-12-31', 'YYYY-MM-DD');

-- 更精确的写法
SELECT * FROM users 
WHERE joined_date >= TO_DATE('2024-12-01', 'YYYY-MM-DD')
  AND joined_date < TO_DATE('2025-01-01', 'YYYY-MM-DD');

坑点5:查询NLS参数

当遇到日期格式莫名其妙对不上时,先查NLS参数:

sql
SELECT * FROM NLS_SESSION_PARAMETERS WHERE PARAMETER LIKE '%DATE%';
SELECT * FROM V$NLS_PARAMETERS WHERE PARAMETER LIKE '%DATE%';

六、高级用法:日期算术与相关函数

6.1 日期加减运算

Oracle中日期可以直接加减天数:

sql
-- 当前时间加10天
SELECT SYSDATE + 10 AS future_date FROM dual;

-- 当前时间减5天
SELECT SYSDATE - 5 AS past_date FROM dual;

-- 加3个月
SELECT ADD_MONTHS(SYSDATE, 3) FROM dual;

-- 减7个月
SELECT ADD_MONTHS(SYSDATE, -7) FROM dual;

6.2 INTERVAL间隔运算

sql
-- 当前时间减7分钟
SELECT SYSDATE, SYSDATE - INTERVAL '7' MINUTE FROM dual;

-- 当前时间减7小时
SELECT SYSDATE - INTERVAL '7' HOUR FROM dual;

-- 当前时间减7天
SELECT SYSDATE - INTERVAL '7' DAY FROM dual;

-- 当前时间减7月
SELECT SYSDATE - INTERVAL '7' MONTH FROM dual;

6.3 LAST_DAY与NEXT_DAY

sql
-- 获取本月最后一天
SELECT LAST_DAY(SYSDATE) FROM dual;
-- 结果:2026-05-31

-- 获取下一个周五
SELECT NEXT_DAY(SYSDATE, 'FRIDAY') FROM dual;
-- 或使用中文
SELECT NEXT_DAY(SYSDATE, '星期五') FROM dual;

6.4 TRUNC截断函数

sql
-- 截断到月份第一天
SELECT TRUNC(SYSDATE, 'MM') FROM dual;
-- 结果:2026-05-01

-- 截断到年份第一天
SELECT TRUNC(SYSDATE, 'YYYY') FROM dual;
-- 结果:2026-01-01

-- 截断到当天(去掉时分秒)
SELECT TRUNC(SYSDATE) FROM dual;

6.5 EXTRACT提取函数

sql
SELECT EXTRACT(YEAR FROM SYSDATE) AS current_year,
       EXTRACT(MONTH FROM SYSDATE) AS current_month,
       EXTRACT(DAY FROM SYSDATE) AS current_day
FROM dual;
-- 结果:2026 | 5 | 22

七、在天翼云Oracle环境中的实践建议

在天翼云上部署Oracle数据库时,我有以下几条实战建议:

第一,统一日期格式标准。 建议在应用初始化时执行:

sql
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_DATE_LANGUAGE = 'SIMPLIFIED CHINESE';

这样可以避免因字符集不同导致的日期解析异常。

第二,所有日期转换必须显式使用TO_DATE。 不要图省事依赖隐式转换,尤其是在多人协作的项目中,隐式转换是Bug的温床。

第三,时间字段一律使用TIMESTAMP而非DATE。 如果你的业务需要毫秒级精度,Oracle提供了TIMESTAMP类型:

sql
SELECT TO_CHAR(CURRENT_TIMESTAMP(3), 'YYYY-MM-DD HH24:MI:SS.FF3') FROM dual;
-- 结果:2026-05-22 15:30:45.123

第四,善用绑定变量。 在应用程序中,不要把日期拼接成SQL字符串,而是使用绑定变量配合TO_DATE:

sql
-- ✅ 推荐
SELECT * FROM orders WHERE order_date = TO_DATE(:date_str, 'YYYY-MM-DD');

-- ❌ 不推荐(有SQL注入风险)
SELECT * FROM orders WHERE order_date = '''' || :date_str || '''';

八、总结

TO_DATE函数看似简单,实则是Oracle日期处理的基石。掌握它,你就掌握了Oracle日期操作的半壁江山。

最后再帮你总结一张速查表:

需求 写法
字符串转日期 TO_DATE('2024-12-11', 'YYYY-MM-DD')
带时间转换 TO_DATE('2024-12-11 14:30:45', 'YYYY-MM-DD HH24:MI:SS')
12小时制 TO_DATE('02:30:00 PM', 'HH:MI:SS AM')
法语月份 TO_DATE('05-Mai-2025', 'DD-Mon-YYYY', 'NLS_DATE_LANGUAGE=FRENCH')
求星期几 TO_CHAR(TO_DATE('2024-12-11','YYYY-MM-DD'), 'DAY')
两日期天数差 SYSDATE - TO_DATE('2024-01-01','YYYY-MM-DD')
月份差 MONTHS_BETWEEN(date1, date2)
0条评论
作者已关闭评论
窝补药上班啊
1432文章数
7粉丝数
窝补药上班啊
1432 文章 | 7 粉丝
原创

Oracle中TO_DATE用法

2026-06-02 17:46:39
0
0

一、TO_DATE函数到底是什么?

简单来说,TO_DATE函数的核心使命只有一个:将字符串转换为Oracle的DATE数据类型。

Oracle内部存储DATE数据时,使用的是一种内部格式,这意味着当你拿到一个字符串形式的日期,比如 '2024-12-11' 或者 'March 17, 2023',你必须通过TO_DATE函数将其转换为DATE类型,才能正确地存储到DATE列中,或者进行日期运算。

1.1 基本语法

sql
TO_DATE(string, format_mask, [nls_language])
参数 说明 是否必填
string 要转换的日期字符串 ✅ 必填
format_mask 指定字符串的日期格式 ✅ 必填
nls_language 可选,指定语言环境 ❌ 可选

重点来了:format_mask参数是整个TO_DATE函数的灵魂。 它告诉Oracle,你给的这个字符串到底长什么样。如果format_mask写错了,轻则返回NULL,重则直接报错。


二、format_mask格式掩码大全

这是本文最核心的部分,我把所有常用的格式掩码整理成表格,建议收藏。

2.1 年份相关

格式符 含义 示例 结果
YYYY 四位年份 2024 2024
YYY 三位年份 024 024
YY 两位年份 24 24
Y 一位年份 4 4
RRRR 两位年份转四位(00-49→20xx,50-99→19xx) 50 1950
IYYY ISO标准四位年份 2024 2024

特别注意RRRR的妙用: 当你只有两位年份时,使用RRRR可以智能判断世纪。比如输入'50',返回1950;输入'24',返回2024。这在处理老旧系统数据时非常实用。

2.2 月份相关

格式符 含义 示例 结果
MM 两位数字月份(01-12) 12 12月
MON 三位英文月份缩写 DEC DEC
MONTH 完整月份名称(空格填充至9字符) DECEMBER DECEMBER
RM 罗马数字月份(I-XII) XII XII

踩坑预警: 如果你的字符串里写的是"December"而不是"DEC",那你必须用MONTH而不是MON。这是新手最常犯的错误之一。

2.3 日期相关

格式符 含义 示例 结果
DD 当月第几天(01-31) 15 15日
DDD 当年第几天(001-366) 365 第365天
DY 星期缩写 MON MON
DAY 星期全名(空格填充至9字符) MONDAY MONDAY
D 星期几(1=周日,7=周六) 2 周一

2.4 时间相关(重中之重)

格式符 含义 示例 结果
HH 或 HH12 12小时制小时(01-12) 02 02
HH24 24小时制小时(00-23) 14 14
MI 分钟(00-59) 30 30分
SS 秒(00-59) 45 45秒
FF 十亿分之一秒(纳秒级) 123456789 纳秒
AM / PM 上午/下午标识 PM 下午

🚨 致命错误警告:分钟必须用MI,不能用MM!

这是我见过最多的错误。在Java里我们习惯写mm表示分钟,但在Oracle SQL中,MM是月份!如果你写成:

sql
-- ❌ 错误写法,会报 ORA-01810 格式代码出现两次
SELECT TO_DATE('2024-12-11 14:30:45', 'YYYY-MM-DD HH24:mm:ss') FROM dual;

正确写法是:

sql
-- ✅ 正确写法
SELECT TO_DATE('2024-12-11 14:30:45', 'YYYY-MM-DD HH24:MI:SS') FROM dual;

记住:Oracle里分钟是MI,不是MM!


三、实战案例:从入门到精通

3.1 基础转换——最常见的场景

sql
-- 将 '2024-12-11' 转换为 DATE 类型
SELECT TO_DATE('2024-12-11', 'YYYY-MM-DD') FROM dual;
-- 结果:11-DEC-24(Oracle默认显示格式)

-- 带时间的转换
SELECT TO_DATE('2024-12-11 14:30:45', 'YYYY-MM-DD HH24:MI:SS') FROM dual;
-- 结果:11-DEC-24 下午 02:30:45

3.2 插入数据时使用TO_DATE

sql
-- 假设有一张用户表 users(id, name, joined_date)
INSERT INTO users (id, name, joined_date) 
VALUES (1, '张三', TO_DATE('2024-12-11', 'YYYY-MM-DD'));

-- 带时间的插入
INSERT INTO users (id, name, joined_date) 
VALUES (2, '李四', TO_DATE('2024-12-11 09:30:00', 'YYYY-MM-DD HH24:MI:SS'));
 

3.3 处理不同语言的月份名称

当你的日期字符串中包含非英文月份名称时,需要使用第三个参数nls_language

sql
-- 法语月份 "Mai" = 五月
SELECT TO_DATE('05-Mai-2025', 'DD-Mon-YYYY', 'NLS_DATE_LANGUAGE=FRENCH') FROM dual;
-- 结果:05-MAY-25

-- 中文环境下
SELECT TO_DATE('2024年12月11日', 'YYYY"年"MM"月"DD"日"', 'NLS_DATE_LANGUAGE=SIMPLIFIED CHINESE') FROM dual;

你也可以在会话级别设置语言:

sql
ALTER SESSION SET NLS_DATE_LANGUAGE = 'AMERICAN';
SELECT TO_CHAR(TO_DATE('2002-08-26', 'YYYY-MM-DD'), 'DAY') FROM dual;
-- 结果:MONDAY(而不是中文的"星期一")

3.4 求某天是星期几

sql
-- 中文环境
SELECT TO_CHAR(TO_DATE('2024-12-11', 'YYYY-MM-DD'), 'DAY', 'NLS_DATE_LANGUAGE=SIMPLIFIED CHINESE') FROM dual;
-- 结果:星期三

-- 英文环境
SELECT TO_CHAR(TO_DATE('2024-12-11', 'YYYY-MM-DD'), 'DAY', 'NLS_DATE_LANGUAGE=AMERICAN') FROM dual;
-- 结果:WEDNESDAY

3.5 计算两个日期之间的天数

sql
-- 当前日期减去指定日期
SELECT FLOOR(SYSDATE - TO_DATE('2024-01-01', 'YYYY-MM-DD')) AS days_diff FROM dual;

-- 两个指定日期之间的天数
SELECT TO_DATE('2024-12-31', 'YYYY-MM-DD') - TO_DATE('2024-01-01', 'YYYY-MM-DD') AS days_diff FROM dual;
-- 结果:365

3.6 计算月份差

sql
-- 使用 MONTHS_BETWEEN 函数
SELECT MONTHS_BETWEEN(TO_DATE('2024-12-31', 'YYYY-MM-DD'), 
                      TO_DATE('2024-01-01', 'YYYY-MM-DD')) AS months_diff 
FROM dual;
-- 结果:12

-- 非整月的情况
SELECT MONTHS_BETWEEN(TO_DATE('2024-02-01', 'YYYY-MM-DD'), 
                      TO_DATE('2024-01-01', 'YYYY-MM-DD')) AS months_diff 
FROM dual;
-- 结果:1.03225806451613(约1.03个月)

3.7 查询某月内排除周末的天数

这是一个非常实用的业务场景——计算工作日天数:

sql
SELECT COUNT(*) AS workdays
FROM (
    SELECT ROWNUM - 1 AS rnum
    FROM all_objects
    WHERE ROWNUM <= TO_DATE('2024-02-28', 'YYYY-MM-DD') - TO_DATE('2024-02-01', 'YYYY-MM-DD') + 1
)
WHERE TO_CHAR(TO_DATE('2024-02-01', 'YYYY-MM-DD') + rnum - 1, 'D') NOT IN ('1', '7');
-- 结果:20(2024年2月1日到28日之间,排除周六周日的工作日天数)

3.8 处理NULL值

sql
-- 查询时需要用 TO_DATE(NULL) 而不是 NULL
SELECT id, active_date FROM table1
UNION
SELECT 1, TO_DATE(NULL) FROM dual;

如果直接写NULL,Oracle可能会因为类型不匹配而报错。


四、TO_DATE与TO_CHAR的黄金搭档

在实际开发中,TO_DATE和TO_CHAR是一对形影不离的好搭档。一个负责"字符→日期",一个负责"日期→字符"。

操作 函数 示例
字符串转日期 TO_DATE TO_DATE('2024-12-11', 'YYYY-MM-DD')
日期转字符串 TO_CHAR TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS')
提取年份 TO_CHAR TO_CHAR(SYSDATE, 'YYYY')
提取月份 TO_CHAR TO_CHAR(SYSDATE, 'MM')
提取日期 TO_CHAR TO_CHAR(SYSDATE, 'DD')
提取小时 TO_CHAR TO_CHAR(SYSDATE, 'HH24')
提取分钟 TO_CHAR TO_CHAR(SYSDATE, 'MI')
提取秒 TO_CHAR TO_CHAR(SYSDATE, 'SS')

实战:自定义格式化输出

sql
SELECT TO_CHAR(SYSDATE, '"今天是" DD"日" MONTH", "YYYY"年"') AS custom_date FROM dual;
-- 结果:今天是 22日 MAY    , 2026年

SELECT TO_CHAR(SYSDATE, 'YYYY"年"MM"月"DD"日" HH24"时"MI"分"SS"秒"') FROM dual;
-- 结果:2026年05月22日 15时30分45秒
 

五、常见坑点与最佳实践

作为一名老开发,我把这些年踩过的坑全部总结给你:

坑点1:格式掩码大小写不敏感,但必须匹配

Oracle的格式掩码不区分大小写,但你的字符串必须和掩码完全对应。比如掩码写的是MONTH,字符串就必须是完整的月份名;写的是MON,字符串就必须是三字母缩写。

坑点2:默认日期格式的陷阱

如果你不指定format_mask,Oracle会使用NLS_DATE_FORMAT参数的默认值,通常是DD-MON-RR。这意味着:

sql
-- 以下写法依赖默认格式,不推荐!
INSERT INTO x VALUES (99, '31-may-98');

-- 推荐写法,显式指定格式
INSERT INTO x VALUES (99, TO_DATE('1998/05/31:12:00:00AM', 'yyyy/mm/dd:hh:mi:ssam'));
 

最佳实践:永远显式指定format_mask,不要依赖隐式转换!

坑点3:AM/PM与HH12/HH24的搭配

sql
-- ✅ 正确:12小时制 + AM/PM
TO_DATE('02:30:00 PM', 'HH:MI:SS AM')

-- ✅ 正确:24小时制,不需要AM/PM
TO_DATE('14:30:00', 'HH24:MI:SS')

-- ❌ 错误:24小时制配了AM/PM,或者12小时制没配AM/PM
TO_DATE('14:30:00 PM', 'HH24:MI:SS AM')  -- 逻辑矛盾!

坑点4:日期比较时的精度问题

当使用BETWEEN进行日期范围查询时,如果不包含时间部分,边界值可能会被意外排除:

sql
-- 假设 joined_date 是 DATE 类型,包含时间
-- 以下查询可能不包含 12月31日 12:00:00 之后的记录
SELECT * FROM users 
WHERE joined_date BETWEEN TO_DATE('2024-12-01', 'YYYY-MM-DD') 
                      AND TO_DATE('2024-12-31', 'YYYY-MM-DD');

-- 更精确的写法
SELECT * FROM users 
WHERE joined_date >= TO_DATE('2024-12-01', 'YYYY-MM-DD')
  AND joined_date < TO_DATE('2025-01-01', 'YYYY-MM-DD');

坑点5:查询NLS参数

当遇到日期格式莫名其妙对不上时,先查NLS参数:

sql
SELECT * FROM NLS_SESSION_PARAMETERS WHERE PARAMETER LIKE '%DATE%';
SELECT * FROM V$NLS_PARAMETERS WHERE PARAMETER LIKE '%DATE%';

六、高级用法:日期算术与相关函数

6.1 日期加减运算

Oracle中日期可以直接加减天数:

sql
-- 当前时间加10天
SELECT SYSDATE + 10 AS future_date FROM dual;

-- 当前时间减5天
SELECT SYSDATE - 5 AS past_date FROM dual;

-- 加3个月
SELECT ADD_MONTHS(SYSDATE, 3) FROM dual;

-- 减7个月
SELECT ADD_MONTHS(SYSDATE, -7) FROM dual;

6.2 INTERVAL间隔运算

sql
-- 当前时间减7分钟
SELECT SYSDATE, SYSDATE - INTERVAL '7' MINUTE FROM dual;

-- 当前时间减7小时
SELECT SYSDATE - INTERVAL '7' HOUR FROM dual;

-- 当前时间减7天
SELECT SYSDATE - INTERVAL '7' DAY FROM dual;

-- 当前时间减7月
SELECT SYSDATE - INTERVAL '7' MONTH FROM dual;

6.3 LAST_DAY与NEXT_DAY

sql
-- 获取本月最后一天
SELECT LAST_DAY(SYSDATE) FROM dual;
-- 结果:2026-05-31

-- 获取下一个周五
SELECT NEXT_DAY(SYSDATE, 'FRIDAY') FROM dual;
-- 或使用中文
SELECT NEXT_DAY(SYSDATE, '星期五') FROM dual;

6.4 TRUNC截断函数

sql
-- 截断到月份第一天
SELECT TRUNC(SYSDATE, 'MM') FROM dual;
-- 结果:2026-05-01

-- 截断到年份第一天
SELECT TRUNC(SYSDATE, 'YYYY') FROM dual;
-- 结果:2026-01-01

-- 截断到当天(去掉时分秒)
SELECT TRUNC(SYSDATE) FROM dual;

6.5 EXTRACT提取函数

sql
SELECT EXTRACT(YEAR FROM SYSDATE) AS current_year,
       EXTRACT(MONTH FROM SYSDATE) AS current_month,
       EXTRACT(DAY FROM SYSDATE) AS current_day
FROM dual;
-- 结果:2026 | 5 | 22

七、在天翼云Oracle环境中的实践建议

在天翼云上部署Oracle数据库时,我有以下几条实战建议:

第一,统一日期格式标准。 建议在应用初始化时执行:

sql
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_DATE_LANGUAGE = 'SIMPLIFIED CHINESE';

这样可以避免因字符集不同导致的日期解析异常。

第二,所有日期转换必须显式使用TO_DATE。 不要图省事依赖隐式转换,尤其是在多人协作的项目中,隐式转换是Bug的温床。

第三,时间字段一律使用TIMESTAMP而非DATE。 如果你的业务需要毫秒级精度,Oracle提供了TIMESTAMP类型:

sql
SELECT TO_CHAR(CURRENT_TIMESTAMP(3), 'YYYY-MM-DD HH24:MI:SS.FF3') FROM dual;
-- 结果:2026-05-22 15:30:45.123

第四,善用绑定变量。 在应用程序中,不要把日期拼接成SQL字符串,而是使用绑定变量配合TO_DATE:

sql
-- ✅ 推荐
SELECT * FROM orders WHERE order_date = TO_DATE(:date_str, 'YYYY-MM-DD');

-- ❌ 不推荐(有SQL注入风险)
SELECT * FROM orders WHERE order_date = '''' || :date_str || '''';

八、总结

TO_DATE函数看似简单,实则是Oracle日期处理的基石。掌握它,你就掌握了Oracle日期操作的半壁江山。

最后再帮你总结一张速查表:

需求 写法
字符串转日期 TO_DATE('2024-12-11', 'YYYY-MM-DD')
带时间转换 TO_DATE('2024-12-11 14:30:45', 'YYYY-MM-DD HH24:MI:SS')
12小时制 TO_DATE('02:30:00 PM', 'HH:MI:SS AM')
法语月份 TO_DATE('05-Mai-2025', 'DD-Mon-YYYY', 'NLS_DATE_LANGUAGE=FRENCH')
求星期几 TO_CHAR(TO_DATE('2024-12-11','YYYY-MM-DD'), 'DAY')
两日期天数差 SYSDATE - TO_DATE('2024-01-01','YYYY-MM-DD')
月份差 MONTHS_BETWEEN(date1, date2)
文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0