1. 程式人生 > >PL/SQL 如何處理兩個timestamp型別的差值

PL/SQL 如何處理兩個timestamp型別的差值

今天遇到一個問題,前端返回請求時間和響應時間給我,而我將兩個差值儲存為以毫秒為單位的number型別存入資料庫。本來以為很簡單 燃鵝0.0..

請求時間和響應時間都是字串表示時間戳型別,我需要將前端傳入的字串轉為時間戳然後才能進行相應的相加減。

例如傳入的請求時間
requestTime :='2017-11-23T11:16:01.960+08:00'
響應時間
responseTime := '2017-10-23T11:16:01.960+08:00'

剛開始我用的是oracle自帶的cast函式,cast函式能夠進行資料型別之間的轉換,格式是CAST ( { expr | ( subquery ) | MULTISET ( subquery ) } AS type_name )


我這裡用的程式碼是
SELECT CAST('2017-11-23T11:16:01.960+08:00' AS TIMESTAMP WITH TIME ZONE) FROM dual;

但是報錯了。。。 提示ORA-01843:無效的月份

--後來試了半天查了資料發現貌似只能支援這種格式
SELECT CAST('23-11月-17 11:16:01.960上午+08:00' AS TIMESTAMP WITH TIME ZONE) FROM dual;

這個就有點坑了。。。PS:當然這個年月日和上下午格式可以通過修改v$nls_parameters表上的NLS_LANGUAGE

欄位

後來發現oracle還有一個to_timestamp函式和to_timestamp_tz函式能夠將字串轉為時間戳型別,其中to_timestamp_tz函式是將字串轉為帶時區的時間戳型別。
兩種函式支援的語法分別是

TO_TIMESTAMP( string1 [, format_mask] ['nlsparam'] )
TO_TIMESTAMP_TZ( string1 [, format_mask] ['nlsparam'] )

格式的話
1. YYYY 四個數字代表年
2. MM 月範圍從01-12
3. MON 代表月的縮寫
4. MONTH

月份的全稱
5. DD 日期
6. HH 小時
7. HH12 12小時制
8. HH24 24小時制
9. MI 分鐘
10. SS
11. TZH 代表時區的小時
12. TZM 代表時區的分鐘

那麼我這裡只需要根據傳入時間的格式就可以轉換為相應的時間戳了,程式碼如下。

requestTimestamp := to_timestamp_tz('2017-11-23T11:16:01.940+08:00', 'YYYY-MM-DDTHH:MI:SS.FF3TZH:TZM');

但是這裡報錯了提示ORA-01821日期格式無法識別

這裡日期和時間之間多了一個字母’T’…查了一下找不到這個東西是什麼意思0.0 我直接replace掉然後再轉換就可以了。

然後cost := responsetTimestamp - requestTimestamp;
本來以為兩個時間戳型別相減會是number型別的。。。額實際上是interval型別(例如 +000000000 00:00:00.000000)

oracle資料庫中使用INTERVAL型別表示兩個時間之間的差值,其中有兩種型別的interval:一種為“年份-月份”,即儲存年份和月份(YYYY-MM);一種為“天-時間”(DD HH:MM:SS),用來儲存天數、小時、分鐘和秒。

那麼我要怎麼才能通過這個interval型別拿到millis呢?
我寫了一個函式,通過獲取差值的天數、小時、分鐘、秒、毫秒,然後 cost := 天數 * 24 * 60 * 60 * 1000 + 小時 * 60 * 60 * 60 + 秒 * 60 * 1000 + 毫秒, 具體程式碼如下

FUNCTION timestamp_difference(p_timestamp_1 timestamp,p_timestamp_2 timestamp) RETURN NUMBER IS
  v_difference VARCHAR2(100);
  v_date VARCHAR2(100);
  v_time VARCHAR2(100);
  v_hour VARCHAR2(10);
  v_minute  VARCHAR2(10);
  v_second  VARCHAR2(100);
  x_response VARCHAR2(1000);
    BEGIN
      IF p_timestamp_1 IS NOT NULL 
      AND p_timestamp_2 IS NOT NULL THEN
        v_difference := to_char(p_timestamp_2 - p_timestamp_1);
        v_date := regexp_substr(v_difference, '[^ ]+', 2, 1);
        v_time := regexp_substr(v_difference, '[^ ]+', 1, 2);
        v_hour := regexp_substr(v_time, '[^:]+', 1, 1);
        v_minute := regexp_substr(v_time, '[^:]+', 1, 2);
        v_second := regexp_substr(v_time, '[^:]+', 1, 3);
        x_response := to_number(v_date) * 24 * 60 * 60 * 1000 
        + to_number(v_hour) * 60 * 60 * 1000 
        + to_number(v_minute) * 60 * 1000 
        + to_number(v_second) * 1000;
      END IF;
      RETURN x_response;
      EXCEPTION WHEN OTHERS THEN
        dbms_output.put_line(SQLERRM);
        RETURN NULL;
    END timestamp_difference;