Skip to content

Instantly share code, notes, and snippets.

@taichi
Last active February 10, 2025 13:00
Show Gist options
  • Save taichi/8a023a2848ac067dda95b917cfd84349 to your computer and use it in GitHub Desktop.
Save taichi/8a023a2848ac067dda95b917cfd84349 to your computer and use it in GitHub Desktop.
UUIDv7 on PostgreSQL without Extension. I recommend using pgcrypto's gen_random_bytes instead of random.
-- Copyright 2025 taichi
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
SELECT encode(
int8send(((extract(epoch from current_timestamp) * 1000)::bigint << 16) | (0x7::bigint << 12) | (floor((EXTRACT(MICROSECONDS FROM current_timestamp) % 1000) / 1000.0 * 4096)::bigint)) || -- msb
int8send((0x2::bigint << 62) | ((random() * 0x3FFFFFFF)::bigint << 32) | ((random() * 0xFFFFFFFF)::bigint)) -- lsb
, 'hex')::uuid;
-- Copyright 2025 taichi
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- UUIDv7 generation
-- https://www.rfc-editor.org/rfc/rfc9562.html
CREATE OR REPLACE FUNCTION uuid_generate_v7() RETURNS uuid
LANGUAGE plpgsql
AS $$
DECLARE
ts timestamptz;
unix_ts_milli bigint;
unix_ts_micro bigint;
msb bigint; -- most significant bits
lsb bigint; -- least significant bits
BEGIN
ts := clock_timestamp();
unix_ts_milli := (extract(epoch from ts) * 1000)::bigint;
unix_ts_micro := floor((EXTRACT(MICROSECONDS FROM ts) % 1000) / 1000.0 * 4096)::bigint;
-- [unix_ts_ms(48bits) | version(4bits) | rand_a(12bits)]
msb := (unix_ts_milli << 16) | -- unix_ts_ms
(0x7::bigint << 12) | -- Version 7
unix_ts_micro; -- Method 3
-- [variant(2bits) | rand_b(62bits)]
lsb := (0x2::bigint << 62) | -- 0b10
((random() * 0x3FFFFFFF)::bigint << 32) |
((random() * 0xFFFFFFFF)::bigint);
RETURN encode(int8send(msb) || int8send(lsb), 'hex')::uuid;
END;
$$;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment