在Oracle数据库开发里,处理周相关的日期计算是常见需求,但默认的日期函数逻辑和国内用户的使用习惯存在差异,比如Oracle默认一周从周日开始,而国内大多习惯周一作为一周起始。下面介绍几种符合中国人习惯的取周日期函数实现方式。

一、获取本周起始日和结束日
1. 周一作为一周起始的情况
国内最常用的周起始规则是周一为第一天,周日最后一天,可以用trunc函数结合日期运算实现:
-- 获取指定日期所在周的周一(周起始日)
-- 入参p_date为要计算的日期,返回该周周一的日期
CREATE OR REPLACE FUNCTION get_week_start_monday(p_date DATE) RETURN DATE IS
v_day_num NUMBER; -- 存储当前日期是周几,1是周日,2是周一...7是周六
BEGIN
-- 获取当前日期对应的周几数字,Oracle中day返回的是1(周日)到7(周六)
v_day_num := TO_CHAR(p_date, 'D');
-- 计算周一的日期:如果当前是周日(v_day_num=1),则减6天,否则减(v_day_num-2)天
IF v_day_num = 1 THEN
RETURN TRUNC(p_date) - 6;
ELSE
RETURN TRUNC(p_date) - (v_day_num - 2);
END IF;
END get_week_start_monday;
/
-- 获取指定日期所在周的周日(周结束日)
CREATE OR REPLACE FUNCTION get_week_end_sunday(p_date DATE) RETURN DATE IS
v_start_date DATE;
BEGIN
-- 先拿到本周周一,再加6天就是周日
v_start_date := get_week_start_monday(p_date);
RETURN v_start_date + 6;
END get_week_end_sunday;
/
-- 测试示例
SELECT
get_week_start_monday(SYSDATE) AS 本周周一,
get_week_end_sunday(SYSDATE) AS 本周周日
FROM dual;2. 周日作为一周起始的情况
部分场景会把周日作为一周的开始,实现逻辑更简单:
-- 获取指定日期所在周的周日(周起始日)
CREATE OR REPLACE FUNCTION get_week_start_sunday(p_date DATE) RETURN DATE IS
v_day_num NUMBER;
BEGIN
v_day_num := TO_CHAR(p_date, 'D');
-- 如果当前是周日,直接返回,否则减(v_day_num-1)天
IF v_day_num = 1 THEN
RETURN TRUNC(p_date);
ELSE
RETURN TRUNC(p_date) - (v_day_num - 1);
END IF;
END get_week_start_sunday;
/
-- 获取指定日期所在周的周六(周结束日)
CREATE OR REPLACE FUNCTION get_week_end_saturday(p_date DATE) RETURN DATE IS
v_start_date DATE;
BEGIN
v_start_date := get_week_start_sunday(p_date);
RETURN v_start_date + 6;
END get_week_end_saturday;
/二、获取日期属于当年的第几周
国内统计周数时,通常要求每年的第一周是包含1月1日的那一周,且周一为周起始,实现如下:
-- 获取指定日期属于当年的第几周,符合国内习惯:周一为起始,第一周包含1月1日
CREATE OR REPLACE FUNCTION get_week_num_of_year(p_date DATE) RETURN NUMBER IS
v_year_start DATE; -- 当年1月1日
v_first_week_start DATE; -- 当年第一周的周一
v_week_num NUMBER;
BEGIN
-- 获取当年1月1日
v_year_start := TO_DATE(TO_CHAR(p_date, 'YYYY') || '0101', 'YYYYMMDD');
-- 计算当年第一周的周一:如果1月1日是周日,第一周周一是1月2日,否则按周几计算
v_first_week_start := get_week_start_monday(v_year_start);
-- 如果1月1日在第一周周一之前,说明第一周属于上一年,调整第一周起始
IF v_year_start < v_first_week_start THEN
v_first_week_start := v_first_week_start - 7;
END IF;
-- 计算周数:(当前日期 - 第一周周一) / 7 向上取整
v_week_num := CEIL((TRUNC(p_date) - v_first_week_start + 1) / 7);
RETURN v_week_num;
END get_week_num_of_year;
/
-- 测试示例
SELECT
TO_CHAR(SYSDATE, 'YYYY') AS 年份,
get_week_num_of_year(SYSDATE) AS 当年第几周
FROM dual;三、使用注意事项
- Oracle的
TO_CHAR(date, 'D')返回值受数据库NLS_TERRITORY参数影响,建议在使用前确认参数配置,或者按照上述逻辑显式计算周几,避免环境差异导致结果错误。 - 函数中的
TRUNC(p_date)是为了去掉日期的时间部分,保证只按日期维度计算,如果需要保留时间可以去掉trunc调用。 - 如果业务场景有特殊周规则,比如要求第一周必须至少有4天在当年,可以调整第一周起始的计算逻辑适配需求。