导航

[转] SQL日期函数dayadd/datediff/datepart

Posted on 2016-11-08 19:05  天一涯  阅读(768)  评论(0编辑  收藏  举报
  1 函数一:
  2 
  3 CREATE OR REPLACE FUNCTION dayadd(p_Component varchar2,
  4                                   p_Number    number,
  5                                   p_Date      date) RETURN DATE IS
  6   /****************************************************************/
  7   /*      该函数为日期计算函数主要是计算〕                              */
  8   /*     从当前日期开始经过多少日、季、月、年等后的日期。                 */
  9   /*     入参说明:p_Component         时间元件,如年月日季度等等       */
 10   /*                 p_Number        加数, 注意:应该为整数(可正可负) */
 11   /*                 p_Date                基准时间                */
 12   /*  注意:其他日期元件,如世纪等等,暂时未考虑                         */
 13   /***************************************************************/
 14  
 15   v_Component       varchar2(10);
 16   v_MiddleNumber    number;
 17   v_ReturnValue_Str varchar2(20); --字符串日期格式
 18   v_ReturnValue     date; --返回日期
 19  
 20 BEGIN
 21   v_Component := upper(ltrim(rtrim(p_Component)));
 22   if v_Component in ('Y', 'YY', 'YEAR', 'YYYY') then
 23     --年情况
 24     v_ReturnValue := add_months(p_Date, p_Number * 12);
 25   elsif v_Component in ('M', 'MM', 'MONTH', 'MON') then
 26     --月情况
 27     v_ReturnValue := add_months(p_Date, p_Number);
 28   elsif v_Component in ('D', 'DD', 'DAY') then
 29     --日情况
 30     v_ReturnValue := p_Date + p_Number;
 31   elsif v_Component in ('H', 'HH', 'HOUR') then
 32     --时情况
 33     v_ReturnValue := p_Date + p_Number / 24;
 34   elsif v_Component in ('MI', 'MINUTE') then
 35     --分情况
 36     v_ReturnValue := p_Date + p_Number / 1440;
 37   elsif v_Component in ('S', 'SS', 'SECOND') then
 38     --秒情况
 39     v_ReturnValue := p_Date + p_Number / 86400;
 40   elsif v_Component in ('Q', 'QQ', 'QUARTER') then
 41     --季度情况
 42     v_ReturnValue := p_Date + p_Number * 3;
 43   elsif v_Component in ('W', 'WW', 'WK', 'WEEK') then
 44     --周情况
 45     v_ReturnValue := p_Date + p_Number * 7;
 46   else
 47     v_ReturnValue := to_date('1-1-1', 'yyyy-mm-dd');
 48   end if;
 49   RETURN v_ReturnValue;
 50 EXCEPTION
 51   WHEN OTHERS THEN
 52     RETURN to_date('1-1-1', 'yyyy-mm-dd'); --例外处理
 53  
 54 END;
 55  
 56  
 57 
 58 函数二:
 59 
 60  
 61 
 62 create or replace function datediff(p_Component   varchar2,
 63                                     p_Subtranhend date,
 64                                     p_Minuend     date) RETURN NUMBER IS
 65   /*************************************************************************/
 66   /*      功    能:返回两个日期之间的天、周、月、年等数量。               */
 67   /*      入参说明: p_Component    时间元件,如年月日季度等等             */
 68   /*                 p_Subtrahend   减数时间                               */
 69   /*                 p_Minuend     被减数时间                              */
 70   /*************************************************************************/
 71  
 72   v_ReturnValue   number; -- 结果数值
 73   v_Component     varchar2(10); --日期组件中间转换形式,截取空格并且转为大写
 74   v_YearNum1      number; --减数年份数
 75   v_YearNum2      number; --被减数年份数
 76   v_MonthNum1     number; --减数月份数
 77   v_MonthNum2     number; --被减数月份数
 78   v_HourNum1      number; --减数时数
 79   v_HourNum2      number; --被减数时数
 80   v_MinuteNum1    number; --减数分钟数
 81   v_MinuteNum2    number; --被减数分钟数
 82   v_SecondNum1    number; --减数秒钟数
 83   v_SecondNum2    number; --减数秒钟数
 84   v_QuarterValue1 number; --减数季度数
 85   v_QuarterValue2 number; --被减数季度数
 86   v_WeekNum1      number; --减数与标准时间周差
 87   v_WeekNum2      number; --被减数与标准时间周差
 88 BEGIN
 89   v_Component := upper(ltrim(rtrim(p_Component)));
 90   if v_Component in ('Y', 'YY', 'YEAR', 'YYYY') then
 91     --年情况 
 92     v_YearNum1    := to_number(to_char(p_Subtranhend, 'YYYY'));
 93     v_YearNum2    := to_number(to_char(p_Minuend, 'YYYY'));
 94     v_ReturnValue := v_YearNum2 - v_YearNum1;
 95   elsif v_Component in ('M', 'MM', 'MONTH', 'MON') then
 96     --月情况
 97     --请注意,这个部分与Oracle内置日期函数MONTH_BETWEEN()不同,忽略了日因素
 98     --而后者的两个日期如都是所在月的最后一天,才返回整数,否则,返回分数
 99     --而且这个分数是以31天作为一个月进行计算的结果
100     v_YearNum1    := to_number(to_char(p_Subtranhend, 'YYYY'));
101     v_YearNum2    := to_number(to_char(p_Minuend, 'YYYY'));
102     v_MonthNum1   := to_number(to_char(p_Subtranhend, 'MM'));
103     v_MonthNum2   := to_number(to_char(p_Minuend, 'MM'));
104     v_ReturnValue := (v_YearNum2 - v_YearNum1) * 12 +
105                      (v_MonthNum2 - v_MonthNum1);
106   elsif v_Component in ('D', 'DD', 'DAY') then
107     --日情况
108     --这里与两个日期直接相减的oracle日期算术也不同,只返回整数天数;
109     --而后者可以返回一天的几分之几(以小数形式表达)
110     v_ReturnValue := to_date(to_char(p_Minuend, 'yyyy-mm-dd'), 'YYYY-MM-DD') -
111                      to_date(to_char(p_Subtranhend, 'yyyy-mm-dd'),
112                              'YYYY-MM-DD');
113   elsif v_Component in ('H', 'HH', 'HOUR') then
114     --时情况
115     --第一步:求出天数
116     v_ReturnValue := (to_date(to_char(p_Minuend, 'yyyy-mm-dd'),
117                               'YYYY-MM-DD') -
118                      to_date(to_char(p_Subtranhend, 'yyyy-mm-dd'),
119                               'YYYY-MM-DD'));
120     --第二步:求出时数
121     v_HourNum1    := to_number(to_char(p_Subtranhend, 'HH24'));
122     v_HourNum2    := to_number(to_char(p_Minuend, 'HH24'));
123     v_ReturnValue := v_ReturnValue * 24 + (v_HourNum2 - v_HourNum1);
124   elsif v_Component in ('MI', 'MINUTE') then
125     --分情况
126     --第一步:求出天数
127     v_ReturnValue := (to_date(to_char(p_Minuend, 'yyyy-mm-dd'),
128                               'YYYY-MM-DD') -
129                      to_date(to_char(p_Subtranhend, 'yyyy-mm-dd'),
130                               'YYYY-MM-DD'));
131     --第二步:求出时数
132     v_HourNum1    := to_number(to_char(p_Subtranhend, 'HH24'));
133     v_HourNum2    := to_number(to_char(p_Minuend, 'HH24'));
134     v_ReturnValue := v_ReturnValue * 24 + (v_HourNum2 - v_HourNum1);
135     --第三步:求出分钟数
136     v_MinuteNum1  := to_number(to_char(p_Subtranhend, 'MI'));
137     v_MinuteNum2  := to_number(to_char(p_Minuend, 'MI'));
138     v_ReturnValue := v_ReturnValue * 60 + (v_MinuteNum2 - v_MinuteNum1);
139   elsif v_Component in ('S', 'SS', 'SECOND') then
140     --秒情况
141     --第一步:求出天数
142     v_ReturnValue := (to_date(to_char(p_Minuend, 'yyyy-mm-dd'),
143                               'YYYY-MM-DD') -
144                      to_date(to_char(p_Subtranhend, 'yyyy-mm-dd'),
145                               'YYYY-MM-DD'));
146     --第二步:求出时数
147     v_HourNum1    := to_number(to_char(p_Subtranhend, 'HH24'));
148     v_HourNum2    := to_number(to_char(p_Minuend, 'HH24'));
149     v_ReturnValue := v_ReturnValue * 24 + (v_HourNum2 - v_HourNum1);
150     --第三步:求出分钟数
151     v_MinuteNum1  := to_number(to_char(p_Subtranhend, 'MI'));
152     v_MinuteNum2  := to_number(to_char(p_Minuend, 'MI'));
153     v_ReturnValue := v_ReturnValue * 60 + (v_MinuteNum2 - v_MinuteNum1);
154     --第四步:求出秒钟数
155     v_SecondNum1  := to_number(to_char(p_Subtranhend, 'SS'));
156     v_SecondNum2  := to_number(to_char(p_Minuend, 'SS'));
157     v_ReturnValue := v_ReturnValue * 60 + (v_SecondNum2 - v_SecondNum1);
158   elsif v_Component in ('Q', 'QQ', 'QUARTER') then
159     --季度情况
160     v_YearNum1      := to_number(to_char(p_Subtranhend, 'YYYY'));
161     v_YearNum2      := to_number(to_char(p_Minuend, 'YYYY'));
162     v_QuarterValue1 := to_number(to_char(p_Subtranhend, 'Q'));
163     v_QuarterValue2 := to_number(to_char(p_Minuend, 'Q'));
164     v_ReturnValue   := (v_YearNum2 - v_YearNum1) * 4 +
165                        (v_QuarterValue2 - v_QuarterValue1);
166   elsif v_Component in ('W', 'WW', 'WK', 'WEEK') then
167     --周情况
168     --一周的起始日期应当为星期日
169     --关于周差的计算,尝试采用中间日期的方法
170     --经查,‘1-1-2’即公元一年1月2日为周日,我们就可以用两个时间分别与其相减求周差
171     --两个结果再相减,即可得到正确的数值
172     v_WeekNum1    := floor((to_date(to_char(p_Subtranhend, 'YYYY-MM-DD'),
173                                     'YYYY-MM-DD') -
174                            to_date('1-1-2', 'YYYY-MM-DD')) / 7);
175     v_WeekNum2    := floor((to_date(to_char(p_Minuend, 'YYYY-MM-DD'),
176                                     'YYYY-MM-DD') -
177                            to_date('1-1-2', 'YYYY-MM-DD')) / 7);
178     v_ReturnValue := v_WeekNum2 - v_WeekNum1;
179   else
180     v_ReturnValue := -88888;
181   end if;
182   RETURN v_ReturnValue;
183 EXCEPTION
184   WHEN OTHERS THEN
185     RETURN - 99999; --例外处理
186 END datediff;
187  
188 函数三:
189 
190  
191 
192 create or replace function datepart(p_Component varchar2, p_Date date)
193   RETURN NUMBER IS
194   /*************************************************************************/
195   /*       功   能:获取某个日期中的部分时间元件(日、月、年、分、秒、等) */
196   /*       入参说明:        p_Component 时间元件,如年月日季度等等        */
197   /*                          p_Date            需要解析的时间             */
198   /*************************************************************************/
199   v_Component   varchar2(10);
200   v_ReturnValue NUMBER;
201 BEGIN
202   v_Component := upper(ltrim(rtrim(p_Component)));
203   if v_Component in ('Y', 'YY', 'YEAR', 'YYYY') then
204     --年情况
205     v_ReturnValue := to_number(to_char(p_Date, 'YYYY'));
206   elsif v_Component in ('M', 'MM', 'MONTH', 'MON') then
207     --月情况
208     v_ReturnValue := to_number(to_char(p_Date, 'MM'));
209   elsif v_Component in ('D', 'DD', 'DAY') then
210     --日情况
211     v_ReturnValue := to_number(to_char(p_Date, 'DD'));
212   elsif v_Component in ('H', 'HH', 'HOUR', 'HH24') then
213     --时情况
214     v_ReturnValue := to_number(to_char(p_Date, 'HH24'));
215   elsif v_Component in ('MI', 'MINUTE') then
216     --分情况
217     v_ReturnValue := to_number(to_char(p_Date, 'MI'));
218   elsif v_Component in ('S', 'SS', 'SECOND') then
219     --秒情况
220     v_ReturnValue := to_number(to_char(p_Date, 'SS'));
221   elsif v_Component in ('Q', 'QQ', 'QUARTER') then
222     --季度情况
223     v_ReturnValue := to_number(to_char(p_Date, 'Q'));
224   elsif v_Component in ('W', 'WW', 'WK', 'WEEK') then
225     --周几情况(周日为第一天)
226     v_ReturnValue := to_number(to_char(p_Date, 'D'));
227   elsif v_Component in ('WEEK_NO') then
228     -- 第几周情况
229     v_ReturnValue := to_number(to_char(p_Date, 'IW'));
230   else
231     v_ReturnValue := -88888;
232   end if;
233  
234   RETURN v_ReturnValue;
235 EXCEPTION
236   WHEN OTHERS THEN
237     RETURN - 99999; --例外处理
238  
239 END datepart;