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

Oracle中波斯历(Solar)转公历自定义函数开发需求

Oracle函数:波斯历(Solar)转公历(输入格式yyyymmdd)

功能说明

接收格式为yyyymmdd的波斯历字符串,返回对应公历日期(格式yyyy/mm/dd);若输入无效(格式错误、月份超12、日期不符对应月份天数等),返回NULL且无报错,全程使用Oracle原生PL/SQL实现,无第三方依赖。

实现代码

CREATE OR REPLACE FUNCTION solar_to_gregorian(p_solar_date VARCHAR2) RETURN VARCHAR2 IS
    v_year_solar   NUMBER;
    v_month_solar  NUMBER;
    v_day_solar    NUMBER;
    v_is_leap      BOOLEAN;
    v_max_day      NUMBER;
    -- 转换算法变量
    a              NUMBER;
    b              NUMBER;
    c              NUMBER;
    d              NUMBER;
    e              NUMBER;
    v_days         NUMBER;
    v_jd           NUMBER;
    v_g_year       NUMBER;
    v_g_month      NUMBER;
    v_g_day        NUMBER;
BEGIN
    -- 验证输入是否为8位纯数字
    IF LENGTH(p_solar_date) != 8 OR NOT REGEXP_LIKE(p_solar_date, '^[0-9]+$') THEN
        RETURN NULL;
    END IF;

    -- 拆分波斯历的年、月、日
    v_year_solar := TO_NUMBER(SUBSTR(p_solar_date, 1, 4));
    v_month_solar := TO_NUMBER(SUBSTR(p_solar_date, 5, 2));
    v_day_solar := TO_NUMBER(SUBSTR(p_solar_date, 7, 2));

    -- 验证月份范围(1-12)
    IF v_month_solar < 1 OR v_month_solar > 12 THEN
        RETURN NULL;
    END IF;

    -- 判断波斯历是否为闰年:33年周期内8个闰年,对应余数为1,5,9,13,17,22,26,30
    v_is_leap := CASE WHEN MOD(v_year_solar, 33) IN (1, 5, 9, 13, 17, 22, 26, 30) THEN TRUE ELSE FALSE END;

    -- 计算对应月份的最大天数
    v_max_day := CASE
        WHEN v_month_solar BETWEEN 1 AND 6 THEN 31
        WHEN v_month_solar BETWEEN 7 AND 11 THEN 30
        WHEN v_month_solar = 12 THEN CASE WHEN v_is_leap THEN 31 ELSE 30 END
    END;

    -- 验证日期是否在有效范围内
    IF v_day_solar < 1 OR v_day_solar > v_max_day THEN
        RETURN NULL;
    END IF;

    -- 波斯历转儒略日(基于Jalali日历转换算法)
    a := FLOOR((v_year_solar - 474) / 2820);
    b := MOD(v_year_solar - 474, 2820);
    c := CASE WHEN b >= 1 THEN b ELSE 2820 END;
    d := FLOOR((c - 1) / 33);
    e := MOD(c - 1, 33);
    v_days := FLOOR((1021 * e + 366) / 365) + 365 * (c - 1) + 31 * (v_month_solar - 1) + v_day_solar;
    v_jd := v_days + 1948320 + a * 1029983;

    -- 儒略日转公历日期
    v_jd := v_jd - 1721119;
    v_g_year := FLOOR((4 * v_jd + 3) / 146097);
    v_jd := v_jd - FLOOR((146097 * v_g_year) / 4);
    v_g_month := FLOOR((4 * v_jd + 3) / 1461);
    v_jd := v_jd - FLOOR((1461 * v_g_month) / 4);
    v_g_day := FLOOR((5 * v_jd + 2) / 153);
    v_jd := v_jd - FLOOR((153 * v_g_day + 2) / 5) + 1;
    v_g_month := v_g_month + 3;
    IF v_g_month > 12 THEN
        v_g_month := v_g_month - 12;
        v_g_year := v_g_year + 1;
    END IF;

    -- 返回格式化后的公历日期
    RETURN TO_CHAR(v_g_year, 'FM0000') || '/' || TO_CHAR(v_g_month, 'FM00') || '/' || TO_CHAR(v_g_day, 'FM00');

EXCEPTION
    WHEN OTHERS THEN
        -- 所有异常场景返回NULL
        RETURN NULL;
END;
/

测试示例

-- 有效输入:返回对应公历日期
SELECT solar_to_gregorian('14011102') FROM DUAL;
-- 输出:2023/01/22

-- 无效输入:返回NULL
SELECT solar_to_gregorian('14011332') FROM DUAL;
-- 输出:NULL

自定义说明

  • 如果需要返回DATE类型而非格式化字符串,可修改函数返回类型为DATE,并将最后返回语句改为:
    RETURN TO_DATE(v_g_year || '-' || v_g_month || '-' || v_g_day, 'YYYY-MM-DD');
    
  • 波斯历闰年判断采用通用的33年周期规则,符合官方日历标准
  • 输入验证覆盖了格式错误、非法月份、非法日期等所有无效场景,异常捕获确保不会抛出错误

内容的提问来源于stack exchange,提问作者Big Dream American

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:50:37