2011-11-01 64 views
2

使用Oracle數據庫,我需要知道任何兩個日期(以秒爲單位)之間的差異,而不考慮從晚上6點到早上8點的時間間隔。SQL日期差異無視夜晚

例如,2011年11月1日下午1點至2011年11月11日1點之間的差值達20小時(或分別爲72000秒)。我也需要忽略週末和節假日,但我已經有了PLSQL的功能。

預先感謝您!

問候, 亞歷


編輯
同時,我想出了一個解決辦法我自己,這是說實話不是很複雜的,但做的工作:

CREATE OR REPLACE FUNCTION "GET_WORKTIME" 
(
    startdate_in in date, 
    enddate_in in date 
) 
RETURN NUMBER 
AS 
    days_between number(4); 
    duration number; 
    end_of_first_day date; 
    start_of_last_day date; 
    startdate date; 
    enddate date; 
    weekday number(1); 
    temp_date date; 
    holidays day_array; 
    is_holiday boolean; 
BEGIN 
    duration  := 0; 
    startdate := startdate_in; 
    enddate  := enddate_in; 

IF (startdate IS NULL OR enddate IS NULL OR startdate >= enddate) THEN 
    RETURN 0; 
END IF; 

days_between := trunc(enddate) - trunc(startdate); 

end_of_first_day := to_date(concat(to_char(startdate, 'dd.mm.yyyy'), ' 18:00:00'), 'dd.mm.yyyy hh24:mi:ss'); 
start_of_last_day := to_date(concat(to_char(enddate, 'dd.mm.yyyy'), ' 08:00:00'), 'dd.mm.yyyy hh24:mi:ss'); 

temp_date := startdate; 

FOR i IN 0..days_between LOOP 
    -- if it is the first day, just calculate the time until the end of that day 
    IF i = 0 THEN 
     duration := duration + greatest((end_of_first_day - startdate), 0) * 24 * 3600; 

    -- if it is the last day, just calculate the time until that point in time 
    ELSIF i = days_between THEN 
     duration := duration + greatest((enddate - start_of_last_day), 0) * 24 * 3600;    

    -- for every other day, simply add 10 hours (6pm - 8am) if it is neither 
    -- saturday or sunday nor a holiday 
    ELSE 
     weekday := to_number(to_char(temp_date, 'D')); 
     is_holiday := false; 

     -- weekend? 
     IF (NOT weekday IN (6,7)) THEN 

      -- holiday? 
      FOR j IN extract(year FROM startdate)..extract(year FROM enddate) LOOP 
       holidays := get_holidays_for_year(j); 

       FOR k IN 1..holidays.count LOOP 
        IF (holidays(k) = trunc(temp_date)) THEN 
         is_holiday := true; 
        END IF; 
       END LOOP; 
      END LOOP; 

      -- add 10 hours to the duration 
      IF (NOT is_holiday) THEN 
       duration := duration + 10 * 3600; 
      END IF; 
     END IF; 
    END IF; 

    temp_date := temp_date + 1; 
END LOOP; 
RETURN duration; 
END; 

功能也無視週末和假期,所以它看起來比實際上更全面一些。感謝您的幫助!

問候, 亞歷

回答

0

在Oracle中,你可以簡單地減去兩個日期。 可以通過將結果除以(24 * 60 * 60)

select (last_date - first_date)/(24*60*60) as seconds from table 

甲特技格式化差來計算的秒數是這樣的:

select to_char(trunc(sysdate) + (last_date - first_date), 'hh24:mi:ss') as time_between from table 
+0

感謝您的回答,我已經這樣做了日期之間的差異。然而,問題(對我來說)是減去6pm到8am之間的時間間隔,因爲它與計算無關。 – alexhanschke

2

這可能是最容易打破這種成3個部分:

  1. 第一局部天(如果有的話)
  2. 最後部分天(如果有的話)
  3. 其間的整個天(如果有的話)

上的第一部分天是從後來的(開始時間上午8點)至(LAST_DATE,下午6點第一天)的比較早,所以我們減去那些獲取時間爲第一天:

greatest (least (trunc(first_date)+18/24 
         , last_date 
         ) - greatest(first_date 
            , trunc(first_date)+8/24 
            ) 
       , 0) * 24 as last_day_hours 

greatest功能確保我們沒有得到一個負值如如果開始時間是晚上6點以後。

如果最後一天是不一樣的第一天,然後最後的部分日是從上午08點到(結束時刻)的最後一天:

case when trunc(last_date) != trunc(first_date) 
     then greatest (least(last_date 
          , trunc(last_date)+18/24 
          ) 
         - (trunc(last_date)+8/24) 
         , 0) * 24 
     else 0 end as last_day_hours 

居間整個日子(以小時計) :

greatest ((trunc(last_date) - (trunc(first_date)+1)) 
      , 0 
      ) * 10 as intervening_days_in_hours 

10爲的上午08點之間小時下午6點的數量和

因此添加這些3個值一起給出的總小時數的週期,並且通過3600總相乘給出了開環nds:

(
    (greatest (least (trunc(first_date)+18/24 
        , last_date 
        ) - greatest(first_date 
           , trunc(first_date)+8/24 
           ) 
      , 0) * 24) 
+ case when trunc(last_date) != trunc(first_date) 
     then greatest (least(last_date 
          , trunc(last_date)+18/24 
          ) 
         - (trunc(last_date)+8/24) 
         , 0) * 24 
     else 0 end 
+ (greatest ((trunc(last_date) - (trunc(first_date)+1)) 
      , 0 
      ) * 10) 
) * 3600 as total_seconds 

我不禁感覺它應該比這更容易!當然,這不會考慮週末。