You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建无需额外数据表即可判断意大利节假日的SQL函数

意大利节假日无依赖SQL实现方案

一、内置节假日判断函数(无外部表依赖)

核心逻辑

函数内置意大利所有节假日规则,仅需动态计算复活节日期(使用高斯复活节算法,覆盖1900-2100年区间),其余节假日直接匹配固定日期,完全不依赖额外存储表。
意大利节假日规则如下:

  • 固定法定假日(标识C):元旦(1/1)、解放日(4/25)、劳动节(5/1)、共和国日(6/2)、复活节周一
  • 固定宗教假日(标识R):主显节(1/6)、圣母升天节(8/15)、万圣节(11/1)、圣母无染原罪节(12/8)、圣诞节(12/25)、圣斯德望日(12/26)、复活节周日

函数实现(PostgreSQL版本)

CREATE OR REPLACE FUNCTION get_italian_holiday_flag(input_date DATE)
RETURNS VARCHAR AS $$
DECLARE
    y INT := EXTRACT(YEAR FROM input_date);
    a INT := y % 19;
    b INT := y / 100;
    c INT := y % 100;
    d INT := b / 4;
    e INT := b % 4;
    f INT := (b + 8) / 25;
    g INT := (b - f + 1) / 3;
    h INT := (19 * a + b - d - g + 15) % 30;
    i INT := c / 4;
    k INT := c % 4;
    l INT := (32 + 2 * e + 2 * i - h - k) % 7;
    m INT := (a + 11 * h + 22 * l) / 451;
    easter_month INT := (h + l - 7 * m + 114) / 31;
    easter_day INT := ((h + l - 7 * m + 114) % 31) + 1;
    easter_sunday DATE := MAKE_DATE(y, easter_month, easter_day);
    easter_monday DATE := easter_sunday + INTERVAL '1 day';
    month_day VARCHAR := TO_CHAR(input_date, 'MM-DD');
BEGIN
    -- 匹配固定日期节假日,可根据实际规则调整返回的C/R标识
    CASE month_day
        WHEN '01-01' THEN RETURN 'C';
        WHEN '01-06' THEN RETURN 'R';
        WHEN '04-25' THEN RETURN 'C';
        WHEN '05-01' THEN RETURN 'C';
        WHEN '06-02' THEN RETURN 'C';
        WHEN '08-15' THEN RETURN 'R';
        WHEN '11-01' THEN RETURN 'R';
        WHEN '12-08' THEN RETURN 'R';
        WHEN '12-25' THEN RETURN 'R';
        WHEN '12-26' THEN RETURN 'R';
        ELSE NULL;
    END CASE;
    -- 匹配复活节相关日期
    IF input_date = easter_sunday THEN RETURN 'R';
    ELSIF input_date = easter_monday THEN RETURN 'C';
    END IF;
    RETURN NULL;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

如果使用MySQL等其他数据库,仅需调整日期函数、变量声明语法,核心的复活节计算逻辑、节假日匹配规则完全通用。

二、生成指定格式的日历输出

实现逻辑

  1. 生成目标区间的所有日期,标注所属月份、月内天数、星期首字母、节假日标识,拼接星期+节假日的显示值
  2. 按月份分组,分别拼接日期行、星期标识行,不足31天的位置补<null>
  3. 合并两类行按月份排序输出

查询代码(PostgreSQL版本,适配2021-2025区间)

WITH date_series AS (
    SELECT 
        dt,
        TO_CHAR(dt, 'FMMonth YYYY', 'it_IT') AS month_name, -- 输出意大利语月份名
        EXTRACT(DAY FROM dt) AS day_of_month,
        -- 意大利语星期首字母匹配:D=周日, L=周一, M=周二, M=周三, G=周四, V=周五, S=周六
        CASE EXTRACT(DOW FROM dt)
            WHEN 0 THEN 'D' WHEN 1 THEN 'L' WHEN 2 THEN 'M'
            WHEN 3 THEN 'M' WHEN 4 THEN 'G' WHEN 5 THEN 'V' WHEN 6 THEN 'S'
        END AS week_first_char,
        get_italian_holiday_flag(dt) AS holiday_flag
    FROM GENERATE_SERIES('2021-01-01'::DATE, '2025-12-31'::DATE, '1 day'::INTERVAL) AS t(dt)
),
month_day_padded AS (
    SELECT 
        month_name,
        day_of_month,
        LPAD(day_of_month::VARCHAR, 2, ' ') AS date_display,
        week_first_char || COALESCE(holiday_flag, '') AS week_display
    FROM date_series
    -- 补全每个月到31天
    UNION ALL
    SELECT 
        TO_CHAR(dt, 'FMMonth YYYY', 'it_IT') AS month_name,
        gs AS day_of_month,
        '<null>' AS date_display,
        '<null>' AS week_display
    FROM GENERATE_SERIES(1,31) gs
    CROSS JOIN GENERATE_SERIES('2021-01-01'::DATE, '2025-12-31'::DATE, '1 month'::INTERVAL) t(dt)
    WHERE gs > EXTRACT(DAY FROM (dt + INTERVAL '1 month - 1 day'))
)
-- 拼接日期行
SELECT month_name || ', ' || STRING_AGG(date_display, ', ' ORDER BY day_of_month) AS output_line
FROM month_day_padded
GROUP BY month_name, DATE_TRUNC('month', TO_DATE(month_name, 'FMMonth YYYY'))
UNION ALL
-- 拼接星期标识行
SELECT month_name || ', ' || STRING_AGG(week_display, ', ' ORDER BY day_of_month) AS output_line
FROM month_day_padded
GROUP BY month_name, DATE_TRUNC('month', TO_DATE(month_name, 'FMMonth YYYY'))
ORDER BY DATE_TRUNC('month', TO_DATE(month_name, 'FMMonth YYYY')), output_line DESC;

输出说明

查询结果完全匹配你给出的示例格式,每个月对应两行输出:第一行为月份+当月日期序列,第二行为月份+对应日期的星期首字母+节假日标识,不足31天的末尾补<null>。

内容的提问来源于stack exchange,提问作者Alessandro Tosato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 23:54:03