在postgresql中从v1 uuid转换或提取timestamptz

时间:2014-06-12 07:12:27

标签: postgresql uuid

我正试图从V1 uuid中提取时间戳,天真地希望这有效:

select '3efe0a20-f1b3-11e3-bb44-14109fec739e'::uuid::timestamp;

这是一个快速示例,展示了如何提取时间,但我希望postgresql内置一些内容而不是创建一次性pl / pgSql函数。 http://play.golang.org/p/XRCooLgfaG

3 个答案:

答案 0 :(得分:12)

我已经使用我的数据库中的uuid对此进行了测试,它似乎工作得非常好,即使没有未签名的bigints

CREATE FUNCTION uuid_timestamp(id uuid) RETURNS timestamptz AS $$
  select TIMESTAMP WITH TIME ZONE 'epoch' +
      (((('x' || lpad(split_part(id::text, '-', 1), 16, '0'))::bit(64)::bigint) +
      (('x' || lpad(split_part(id::text, '-', 2), 16, '0'))::bit(64)::bigint << 32) +
      ((('x' || lpad(split_part(id::text, '-', 3), 16, '0'))::bit(64)::bigint&4095) << 48) - 122192928000000000) / 10000000 ) * INTERVAL '1 second';    
$$ LANGUAGE SQL
  IMMUTABLE
  RETURNS NULL ON NULL INPUT;

我在2099年创建的V1 uuid!

select uuid_timestamp('6d248400-65b7-1243-a57a-14109fec739e');
uuid_timestamp     
------------------------
 2099-08-01 11:30:00-07
(1 row)

答案 1 :(得分:0)

这是一个粗略的pl / pgsql实现,它将(timestamp,clock_seq,macaddr)转换为版本1 uuid。

session

答案 2 :(得分:0)

根据我们的测试,@ Krut实现的替代方法要快很多:

CREATE OR REPLACE FUNCTION uuid_timestamp(uuid UUID) RETURNS TIMESTAMPTZ AS $$
DECLARE
  bytes bytea; 
BEGIN
  bytes := uuid_send(uuid);
  RETURN to_timestamp(
             (
                 (
                   (get_byte(bytes, 0)::bigint << 24) |
                   (get_byte(bytes, 1)::bigint << 16) |
                   (get_byte(bytes, 2)::bigint <<  8) |
                   (get_byte(bytes, 3)::bigint <<  0)
                 ) + (
                   ((get_byte(bytes, 4)::bigint << 8 |
                   get_byte(bytes, 5)::bigint)) << 32
                 ) + (
                   (((get_byte(bytes, 6)::bigint & 15) << 8 | get_byte(bytes, 7)::bigint) & 4095) << 48
                 ) - 122192928000000000
             ) / 10000 / 1000::double precision
         );
END
$$ LANGUAGE plpgsql
IMMUTABLE PARALLEL SAFE
RETURNS NULL ON NULL INPUT;

请注意,它只会执行毫秒精度,因此您可能需要将函数的“ / 10000/1000 :: double precision”位调整为仅“ / 10000000 :: double precision”。

示例:

=> select uuid_timestamp(uuid_generate_v1()), now();
       uuid_timestamp       |              now
----------------------------+-------------------------------
 2020-04-29 17:40:54.519+00 | 2020-04-29 17:40:54.518204+00
(1 row)

此外,还假设输入为v1。如果您尝试给它一个类似v4的东西,那么如果不是v1,期望得到奇怪的答案或将功能更改为RAISE。

=> select uuid_timestamp(uuid_generate_v4());
       uuid_timestamp
----------------------------
 4251-12-19 17:38:34.866+00
(1 row)