我需要在oracle中查找特定年份,星期和工作日的日期。 oracle中是否对此具有内置功能?或我该如何实现?
例如:如果Year = 2019,Week = 22,Day = 2(Tuesday),则日期应为'28 -05-2019'。
答案 0 :(得分:2)
根据ISO-8601,假设“周”和“年”表示星期和年份,则可以使用此功能:
CREATE OR REPLACE FUNCTION ISOWeekDate(YEAR INTEGER, WEEK INTEGER, DAY INTEGER) RETURN DATE DETERMINISTIC IS
res DATE;
BEGIN
IF WEEK > 53 OR WEEK < 1 THEN
RAISE VALUE_ERROR;
END IF;
res := NEXT_DAY(TO_DATE( YEAR || '0104', 'YYYYMMDD' ) - INTERVAL '7' DAY, 'MONDAY') + ( WEEK - 1 ) * 7;
IF TO_CHAR(res, 'fmIYYY') = YEAR THEN
RETURN res + DAY - 1;
ELSE
RAISE VALUE_ERROR;
END IF;
END ISOWeekDate;
答案 1 :(得分:1)
我认为没有内置功能,您将必须自己构建一个。 以下是您可以使用的解决方案之一。
WITH FUNCTION getDate(p_year IN NUMBER, p_weeks IN NUMBER, p_day in NUMBER) RETURN DATE
IS
v_tmp date;
v_day number;
BEGIN
v_tmp := to_date('01/01/'||to_char(p_year),'dd/mm/yyyy');
v_day := to_char(v_tmp,'D');
RETURN v_tmp+(p_weeks-1)*7+p_day-(v_day)+1;
END;
SELECT getDate(2019,22,2)
FROM DUAL;
/
根据我的NLS_TERRITORY设置,Oracle从星期日开始将星期几编号,但是从您的示例中,您似乎将星期一视为星期几。因此,对函数进行了相同的调整以返回预期的结果。
另外,请注意with子句功能是Oracle 12c的新功能,如果碰巧使用了旧版本的Oracle,则必须在调用存储功能之前先创建它。
答案 2 :(得分:0)
从逻辑上讲,ISO周数是该(格里高利历)日历年中星期四的发生时间。 ISO周的ISO年,是该ISO周的星期四所在的公历年。
在ISO模式中,周始终包含7天。每周从星期一开始,在星期日结束,并且该周的天数为1-7。
该工作日编号方案通常与内置WEEKDAY
函数返回的编号方案不同,并且在不同的软件包中类似(或需要特定的数据库设置),这一点要注意。您将需要一个函数,该函数可以根据ISO编号方案返回特定日期的工作日。
一年中的第一个星期四可以在1月1日至1月7日的任何范围内发生。
如果第一个星期四是1月1日,那么该年的第一个ISO周将包括上一个公历年的天数(29 / 31-Dec)。
如果第一个星期四是1月7日,那么前一个公历年份的ISO最后一周将包括当前公历年的日期(01 / 03-Jan)。
如果第一个星期四是1月4日,则意味着一年中的第一个ISO周从星期一1月1日开始。
要设计算法,最简单的方法可能是确定给定年份的1月4日是哪个工作日,然后应用以下计算4 - weekday
。如果发现04年1月4日的工作日为星期四,则结果为0。如果为星期一,则结果为3(4-1)。如果是星期日,则结果将是-3(4-7)。我们将存储此偏移量,以供下一步使用。
我们可以从ISO周和天数得出一个临时的年度偏移量,如下所示:(((iso_week - 1) * 7) - (4 - iso_day))
。
然后,我们将在第一阶段中得出的偏移量用于年度的最终偏移量。与给定的公历年的1月4日相比,存在偏差。如果相关日期在给定年份的1月4日之前,则此偏移量可能为负数。
鉴于该年的偏移量,我们可以使用内置函数生成给定年份的01月,并应用该年的偏移量来生成最终的公历日期。
例如,给定2019-W01-1。
2019-01-04是星期五,所以它的工作日是5。第一步的结果是-1(4-5)。第二步的结果是-3(((1-1)* 7)-(4-1))。将它们相加得出的年度偏移量为-4。 2019年1月4日在2018年12月31日被-4个结果抵消。
那是我们的结果:2019-W01-1 = 2018-12-31。