从oracle plsql中的ulid提取时间戳
有没有办法从Oracle PL/SQL中的数据中提取时间戳?我们最近不得不与一家供应商打交道,该供应商为唯一的变更序列标识符提供ulid变更数据,并且需要提取时间戳。正如creator的github中提到的,解决方案存在于其他语言中,但我们希望能够在Oracle中运行转换。这花了太长时间来实现,我想节省其他人自己尝试的时间从oracle plsql中的ulid提取时间戳,oracle,plsql,Oracle,Plsql,有没有办法从Oracle PL/SQL中的数据中提取时间戳?我们最近不得不与一家供应商打交道,该供应商为唯一的变更序列标识符提供ulid变更数据,并且需要提取时间戳。正如creator的github中提到的,解决方案存在于其他语言中,但我们希望能够在Oracle中运行转换。这花了太长时间来实现,我想节省其他人自己尝试的时间 DECLARE p_Ulid VARCHAR2(200) := '01EG664DVCY5NTH7WFN57PA7TM'; --Example ULID FU
DECLARE
p_Ulid VARCHAR2(200) := '01EG664DVCY5NTH7WFN57PA7TM'; --Example ULID
FUNCTION Get_Ulid_Ts(p_In VARCHAR2) RETURN TIMESTAMP
WITH TIME ZONE IS
Dec_Value NUMBER := 0;
t_Time_Part VARCHAR2(10) := Substr(p_In, 0, 10); --First 10 characters are the timestamp
Ret TIMESTAMP WITH TIME ZONE := To_Timestamp_Tz('19700101 +00:00', 'yyyymmdd TZH:TZM'); --Unix timestamp sentinal
c_Base NUMBER := 32;
c_Base32 VARCHAR2(32) := '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; --Crockford's base32
TYPE B32_Map_Typ IS TABLE OF NUMBER INDEX BY VARCHAR2(1);
B32map B32_Map_Typ;
BEGIN
--initialize base32 map
FOR i IN 0 .. Length(c_Base32) - 1
LOOP
B32map(Substr(c_Base32, i + 1, 1)) := i;
END LOOP;
--convert base 32 to base 10
FOR i IN 1 .. Length(t_Time_Part)
LOOP
Dec_Value := Dec_Value +
Power(c_Base, i - 1) *
B32map(Substr(t_Time_Part, -i, 1));
END LOOP;
--add to unix timestamp sentinal
Ret := Ret +numtodsinterval(((Dec_Value/ 1000) ),'SECOND') ;
RETURN Ret;
END;
BEGIN
--ISO8601 timestamp formats
EXECUTE IMMEDIATE q'!alter session set nls_timestamp_format = 'YYYY-MM-DD"T"HH24:MI:SS.ff3"Z"' !';
EXECUTE IMMEDIATE q'!alter session set nls_timestamp_tz_format = 'YYYY-MM-DD"T"HH24:MI:SS.ff3 TZR' !';
--test function
Dbms_Output.Put_Line(Get_Ulid_Ts(p_Ulid));
Dbms_Output.Put_Line(Get_Ulid_Ts(p_Ulid) At TIME ZONE
'America/New_York');
END;
/
如果有人有更有效的方法,请评论。(我也没有足够的声誉在StackOverflow中创建“ulid”标记)
以下是一个稍微提高性能的软件包变体:
CREATE OR REPLACE PACKAGE LUTOOLS.Ulid IS
Nls_Timestamp_Format VARCHAR2(64) := 'YYYY-MM-DD"T"HH24:MI:SS.ff3"Z"';
Nls_Timestamp_Tz_Format VARCHAR2(64) := 'YYYY-MM-DD"T"HH24:MI:SS.ff3"Z"';
TYPE B32_Map_Typ IS TABLE OF NUMBER INDEX BY VARCHAR2(1);
B32map B32_Map_Typ;
c_Base NUMBER := 32;
c_Base32 VARCHAR2(32) := '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; --Crockford's base32
FUNCTION Get_Ulid_Ts(p_In VARCHAR2) RETURN TIMESTAMP
WITH TIME ZONE;
END Ulid;
/
CREATE OR REPLACE PACKAGE BODY LUTOOLS.Ulid IS
FUNCTION Get_Ulid_Ts(p_In VARCHAR2) RETURN TIMESTAMP
WITH TIME ZONE IS
Dec_Value NUMBER := 0;
t_Time_Part VARCHAR2(10) := Substr(p_In, 0, 10); --First 10 characters are the timestamp
Ret TIMESTAMP WITH TIME ZONE := To_Timestamp_Tz('19700101 +00:00', 'yyyymmdd TZH:TZM');
BEGIN
--convert base 32 to base 10
FOR i IN 1 .. Length(t_Time_Part)
LOOP
Dec_Value := Dec_Value +
Power(c_Base, i - 1) *
B32map(Substr(t_Time_Part, -i, 1));
END LOOP;
--add to unix timestamp sentinal
Ret := Ret + Numtodsinterval(((Dec_Value / 1000)), 'SECOND');
RETURN Ret;
END;
BEGIN
--initialize base32 map
FOR i IN 0 .. Length(c_Base32) - 1
LOOP
B32map(Substr(c_Base32, i + 1, 1)) := i;
END LOOP;
END Ulid;
/
已在添加程序包