ORACLE 时间操作

功能: 时间维度在数据仓库中应用非常广泛.面对用户关于不同时间维度的分析。需要对时间处理很了解。

 

用法:1. 当前时间

               select sysdate from dual;   2012-2-17 17:02:02

           2.  某天是星期几

                SELECT to_char(SYSDATE,'day') FROM dual ;   星期五  --显示的是中文(注意跟参数NLS_DATE_LANGUAGE有不关 我的是SIMPLIFIED CHINESE)

                SELECT to_char(SYSDATE,'day', 'nls_date_language=american') FROM dual ;  friday  --显示的是英文

           3.   两个日期相差几天

                SELECT abs(floor(SYSDATE-to_date('20120331','yyyymmdd')))  FROM dual;  43

          3.  两个日期相差月数

               SELECT abs(months_between(to_date('20111214','yyyymmdd'),SYSDATE)) FROM dual;        2.1

         4.  某天下个星期几的日期

             SELECT next_day(SYSDATE,'星期五')  FROM dual;      2012-2-24 17:19:30      

         5.  trunc处理时间

             a.  SELECT trunc(SYSDATE,'yy') FROM dual ;     2012-1-1

             b.  SELECT trunc(SYSDATE,'MM') FROM dual;   2012-2-1

            c.    SELECT trunc(SYSDATE,'DAY') FROM dual;  2012-2-12

            d.    SELECT trunc(SYSDATE,'DD') FROM dual;    2012-2-17

       6.  某天是该月第几天

           SELECT to_char(SYSDATE,'DD') FROM dual;        17

      7 . 某天是该年第几天

           SELECT to_char(SYSDATE,'DDD') FROM dual; 048

   继续补充: sysdate =20120221

     8.  某天是该月的第几周(月内周)

          SELECT CEIL((SYSDATE-NEXT_DAY(TRUNC(SYSDATE,'MM'),'星期一')+1)/7+1) FROM dual;   结果:  4

    9 . 某天是该年的第几周(年内周)

         SELECT CEIL((SYSDATE-NEXT_DAY(TRUNC(SYSDATE,'yy'),'星期一')+1)/7+1) FROM dual;       结果: 9

    10.  某天是该年的第几季度

          SELECT to_char(SYSDATE,'Q') FROM DUAL ;  结果:  1

  

 11. 计算农历日期。需要建立一个函数, 一张临时表及临时表数据

    临时表:  

  create table P_MID_LUNAR_CALENDAR
(
  NL_YEAR   NUMBER(38),
  NL_YEAR_H CHAR(7),
  NL_YEAR_D NUMBER(38)
);

comment on table P_MID_LUNAR_CALENDAR
  is '时间维度表中节假日使用';
-- Add comments to the columns
comment on column P_MID_LUNAR_CALENDAR.NL_YEAR
  is '农历年';
comment on column P_MID_LUNAR_CALENDAR.NL_YEAR_H
  is '农历年对应的16进制数';
comment on column P_MID_LUNAR_CALENDAR.NL_YEAR_D
  is '农历年对应的10进制数';

 

临时表数据:

NL_YEARNL_YEAR_HNL_YEAR_D
19000x04bd819416
19010x04ae019168
19020x0a57042352
19030x054d521717
19040x0d26053856
19050x0d95055632
19060x1655491476
19070x056a022176
19080x09ad039632
19090x055d221970
19100x04ae019168
19110x0a5b642422
19120x0a4d042192
19130x0d25053840
19140x1d255119381
19150x0b54046400
19160x0d6a054944
19170x0ada244450
19180x095b038320
19190x1497784343
19200x0497018800
19210x0a4b042160
19220x0b4b546261
19230x06a5027216
19240x06d4027968
19250x1ab54109396
19260x02b6011104
19270x0957038256
19280x052f221234
19290x0497018800
19300x0656625958
19310x0d4a054432
19320x0ea5059984
19330x06e9528309
19340x05ad023248
19350x02b6011104
19360x186e3100067
19370x092e037600
19380x1c8d7116951
19390x0c95051536
19400x0d4a054432
19410x1d8a6120998
19420x0b55046416
19430x056a022176
19440x1a5b4107956
19450x025d09680
19460x092d037584
19470x0d2b253938
19480x0a95043344
19490x0b55746423
19500x06ca027808
19510x0b55046416
19520x1535586869
19530x04da019872
19540x0a5d042448
19550x1457383315
19560x052d021200
19570x0a9a843432
19580x0e95059728
19590x06aa027296
19600x0aea644710
19610x0ab5043856
19620x04b6019296
19630x0aae443748
19640x0a57042352
19650x0526021088
19660x0f26362051
19670x0d95055632
19680x05b5723383
19690x056a022176
19700x096d038608
19710x04dd519925
19720x04ad019152
19730x0a4d042192
19740x0d4d454484
19750x0d25053840
19760x0d55854616
19770x0b54046400
19780x0b5a046496
19790x195a6103846
19800x095b038320
19810x049b018864
19820x0a97443380
19830x0a4b042160
19840x0b27a45690
19850x06a5027216
19860x06d4027968
19870x0af4644870
19880x0ab6043872
19890x0957038256
19900x04af519189
19910x0497018800
19920x064b025776
19930x074a329859
19940x0ea5059984
19950x06b5827480
19960x055c021952
19970x0ab6043872
19980x096d538613
19990x092e037600
20000x0c96051552
20010x0d95455636
20020x0d4a054432
20030x0da5055888
20040x0755230034
20050x056a022176
20060x0abb743959
20070x025d09680
20080x092d037584
20090x0cab551893
20100x0a95043344
20110x0b4a046240
20120x0baa447780
20130x0ad5044368
20140x055d921977
20150x04ba019360
20160x0a5b042416
20170x1517686390
20180x052b021168
20190x0a93043312
20200x0795431060
20210x06aa027296
20220x0ad5044368
20230x05b5223378
20240x04b6019296
20250x0a6e642726
20260x0a4e042208
20270x0d26053856
20280x0ea6560005
20290x0d53054576
20300x05aa023200
20310x076a330371
20320x096d038608
20330x04bd719415
20340x04ad019152
20350x0a4d042192
20360x1d0b6118966
20370x0d25053840
20380x0d52054560
20390x0dd4556645
20400x0b5a046496
20410x056d022224
20420x055b221938
20430x049b018864
20440x0a57742359
20450x0a4b042160
20460x0aa5043600
20470x1b255111189
20480x06d2027936
20490x0ada044448

 

函数代码: 

CREATE OR REPLACE FUNCTION Fun_GetLunar(i_SolarDay DATE) RETURN VARCHAR2
/**
  *@功能:   算阳历1900/01/31 - 2050/01/22间某一天对应的阴历是多少
  *@原理    在一张表中用10进制格式保存某个农历年每月大小,有无闰月,闰月大小信息
            1.用12个2进制位来表示某个农历年每月的大小,大月记为1,否则为0
            2.用低4位来表示闰月的月份,没有闰月记为0
            3.用一个高位表示闰月的大小,闰月大记为0,闰月小或无闰月记为0
            4.再将该2进制数转化为10进制,存入表中
            农历2000年: 0 110010010110 0000 -> 0x0c960 -> 51552
             农历2001年: 0 110110010101 0100 -> 0x0d954 -> 55636
            采用查表的方式计算出农历日期
  *@性能参考: 估计运行时间:约10s
  **/
 AS
  v_OffSet        INT;
  v_Lunar         INT; -- 农历年是否含闰月,几月是闰月,闰月天数,其它月天数
  v_YearDays      INT; -- 农历年所含天数
  v_MonthDays     INT; -- 农历月所含天数
  v_LeapMonthDays INT; -- 农历闰月所含天数
  v_LeapMonth     INT; -- 农历年闰哪个月 1-12 , 没闰传回 0
  v_LeapFlag      INT; -- 某农历月是否为闰月  1:是  0:不是
  v_MonthNo       INT; -- 某农历月所对应的2进制数 如农历3月: 001000000000
  i               INT;
  j               INT;
  k               INT;

  v_Year  INT; -- i_SolarDay 对应的农历年
  v_Month INT; -- i_SolarDay 对应的农历月
  v_Day   INT; -- i_SolarDay 对应的农历日

  o_OutputDate VARCHAR2(25); -- 返回值  格式:农历 ****年 **(闰)月 **日

  e_ErrMsg VARCHAR2(200);
  e_ErrDate EXCEPTION;
BEGIN

  --输入参数判断
  IF i_SolarDay < TO_DATE('1900-01-31', 'YYYY-MM-DD') OR
     i_SolarDay >= TO_DATE('2050-01-23', 'YYYY-MM-DD') THEN
    RAISE e_ErrDate;
  END IF;

  -- i_SolarDay 到 1900-01-30(即农历1900-01-01的前一天) 的天数
  v_OffSet := TRUNC(i_SolarDay, 'DD') - TO_DATE('1900-01-30', 'YYYY-MM-DD');

  -- 确定农历年开始
  i := 1900;
  WHILE i < 2050 AND v_OffSet > 0 LOOP
    v_YearDays      := 348; --  29*12 以每年12个农历月,每个农历月含29个农历日为基数
    v_LeapMonthDays := 0;

    -- 取出农历年是否含闰月,几月是闰月,闰月天数,其它月天数
    -- 如农历2001年: 0x0d954(16进制) -> 55636(10进制) -> 0 110110010101 0100(2进制)
    -- 1,2,4,5,8,10,12月大, 3,6,7,9,11月小, 4月为闰月,闰月小
    SELECT nl_year_d
      INTO v_Lunar
      FROM P_MID_LUNAR_CALENDAR
     WHERE nl_year = i;

    -- 传回农历年的总天数
    j := 32768; --   100000000000 0000 -> 32768
    -- 0 110110010101 0100 -> 55636(农历2001年)
    -- 依次判断v_Lunar年个月是否为大月,是则加一天
    WHILE j > 8 LOOP
      -- 闰月另行判断 8 -> 0 000000000000 1000
      IF BITAND(v_Lunar, j) + 0 > 0 THEN
        v_YearDays := v_YearDays + 1;
      END IF;
      j := j / 2; -- 判断下一个月是否为大
    END LOOP;

    -- 传回农历年闰哪个月 1-12 , 没闰传回 0   15 -> 1 0000
    v_LeapMonth := BITAND(v_Lunar, 15) + 0;

    -- 传回农历年闰月的天数 ,加在年的总天数上
    IF v_LeapMonth > 0 THEN
      -- 判断闰月大小 65536 -> 1 000000000000 0000
      IF BITAND(v_Lunar, 65536) + 0 > 0 THEN
        v_LeapMonthDays := 30;
      ELSE
        v_LeapMonthDays := 29;
      END IF;
      v_YearDays := v_YearDays + v_LeapMonthDays;
    END IF;

    v_OffSet := v_OffSet - v_YearDays;
    i        := i + 1;
  END LOOP;

  IF v_OffSet <= 0 THEN
    -- i_SolarDay 在所属农历年(即i年)中的第 v_OffSet 天
    v_OffSet := v_OffSet + v_YearDays;
    i        := i - 1;
  END IF;
  -- 确定农历年结束
  v_Year := i;

  -- 确定农历月开始
  i := 1;
  SELECT nl_year_d
    INTO v_Lunar
    FROM P_MID_LUNAR_CALENDAR
   WHERE nl_year = v_Year;

  -- 判断那个月是润月
  -- 如农历2001年 (55636,15 -> 0 1101100101010100, 1111 -> 4) 即润4月,且闰月小
  v_LeapMonth := BITAND(v_Lunar, 15) + 0;
  v_LeapFlag  := 0;

  WHILE i < 13 AND v_OffSet > 0 LOOP
    -- 判断是否为闰月
    v_MonthDays := 0;
    IF (v_LeapMonth > 0 AND i = (v_LeapMonth + 1) AND v_LeapFlag = 0) THEN
      -- 是闰月
      i          := i - 1;
      k          := i; -- 保存是闰月的时i的值
      v_LeapFlag := 1;
      -- 传回农历年闰月的天数
      IF BITAND(v_Lunar, 65536) + 0 > 0 THEN
        v_MonthDays := 30;
      ELSE
        v_MonthDays := 29;
      END IF;

    ELSE
      -- 不是闰月
      j         := 1;
      v_MonthNo := 65536;
      -- 计算 i 月对应的2进制数 如农历3月: 001000000000
      WHILE j <= i LOOP
        v_MonthNo := v_MonthNo / 2;
        j         := j + 1;
      END LOOP;
      -- 计算农历 v_Year 年 i 月的天数
      IF BITAND(v_Lunar, v_MonthNo) + 0 > 0 THEN
        v_MonthDays := 30;
      ELSE
        v_MonthDays := 29;
      END IF;
    END IF;

    -- 解除闰月
    IF v_LeapFlag = 1 AND i = v_LeapMonth + 1 THEN
      v_LeapFlag := 0;
    END IF;
    v_OffSet := v_OffSet - v_MonthDays;
    i        := i + 1;
  END LOOP;

  IF v_OffSet <= 0 THEN
    -- i_SolarDay 在所属农历月(即i月)中的第 v_OffSet 天
    v_OffSet := v_OffSet + v_MonthDays;
    i        := i - 1;
  END IF;

  -- 确定农历月结束
  v_Month := i;

  -- 确定农历日结束
  v_Day := v_OffSet;

  -- 格式化返回值
  o_OutputDate := '农历 ' || TO_CHAR(v_Year) || '年 ';
  IF k = i THEN
    o_OutputDate := o_OutputDate || LPAD(TO_CHAR(v_Month), 2, '0') ||
                    '(润)月 ';
  ELSE
    o_OutputDate := o_OutputDate || LPAD(TO_CHAR(v_Month), 2, '0') || '月 ';
  END IF;
  o_OutputDate := o_OutputDate || LPAD(TO_CHAR(v_Day), 2, '0') || '日';

  RETURN o_OutputDate;

EXCEPTION
  WHEN e_Errdate THEN
    RETURN '日期错误! 有效范围(阳历): 1900/01/31 - 2050/01/22';
  WHEN OTHERS THEN
    e_ErrMsg := SUBSTR(SQLERRM, 1, 200);
    RETURN e_ErrMsg;
END Fun_GetLunar;

 

 

   

         

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值