Skip to content

Commit f4f56de

Browse files
authored
Add uuid1_to_uuid6() function (#107)
1 parent 1cde634 commit f4f56de

4 files changed

Lines changed: 68 additions & 9 deletions

File tree

README.md

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,24 @@ pip install uuid6
1818
## Usage
1919

2020
```python
21-
from uuid6 import uuid6, uuid7, uuid8
21+
import uuid6
2222

23-
my_uuid = uuid6()
23+
my_uuid = uuid6.uuid6()
2424
print(my_uuid)
25-
assert my_uuid < uuid6()
25+
assert my_uuid < uuid6.uuid6()
2626

27-
my_uuid = uuid7()
27+
my_uuid = uuid6.uuid7()
2828
print(my_uuid)
29-
assert my_uuid < uuid7()
29+
assert my_uuid < uuid6.uuid7()
3030

31-
my_uuid = uuid8()
31+
my_uuid = uuid6.uuid8()
3232
print(my_uuid)
33-
assert my_uuid < uuid8()
33+
assert my_uuid < uuid6.uuid8()
34+
35+
import uuid
36+
37+
my_uuid = uuid.UUID(hex="C232AB00-9414-11EC-B3C8-9E6BDECED846")
38+
assert uuid6.uuid1_to_uuid6(my_uuid) == uuid.UUID(hex="1EC9414C-232A-6B00-B3C8-9E6BDECED846")
3439
```
3540

3641
## Which UUID version should I use?
@@ -41,6 +46,24 @@ UUID version 7 features a time-ordered value field derived from the widely imple
4146

4247
If your use case requires greater granularity than UUID version 7 can provide, you might consider UUID version 8. UUID version 8 doesn't provide as good entropy characteristics as UUID version 7, but it utilizes timestamp with nanosecond level of precision.
4348

49+
## Functions
50+
51+
### uuid6.uuid1_to_uuid6(*uuid1*)
52+
53+
Generate a UUID version 6 object from a UUID version 1 object.
54+
55+
### uuid6.uuid6(*clock_seq=None*)
56+
57+
Generate a UUID from a random number, sequence number, and the current time. If *clock_seq* is given, it is used as the sequence number; otherwise a random 14-bit sequence number is chosen.
58+
59+
### uuid6.uuid7()
60+
61+
Generate a UUID from a random number, and the current time.
62+
63+
### uuid6.uuid8()
64+
65+
Generate a UUID from a random number, and the current time.
66+
4467
## UUID Version 6
4568

4669
UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. Systems that do not involve legacy UUIDv1 **SHOULD** use UUIDv7 instead.

src/uuid6/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ def _subsec_encode(value: int) -> int:
7878
return value * 2**20 // 10**6
7979

8080

81+
def uuid1_to_uuid6(uuid1: uuid.UUID) -> UUID:
82+
r"""Generate a UUID version 6 object from a UUID version 1 object."""
83+
if uuid1.version != 1:
84+
raise ValueError("given UUID's version number must be 1")
85+
timestamp = uuid1.time
86+
time_high_and_time_mid = timestamp >> 12
87+
time_low_and_version = timestamp & 0x0FFF
88+
uuid_int = time_high_and_time_mid << 80
89+
uuid_int |= time_low_and_version << 64
90+
uuid_int |= uuid1.clock_seq << 48
91+
uuid_int |= uuid1.node
92+
return UUID(int=uuid_int, version=6, is_safe=uuid1.is_safe)
93+
94+
8195
_last_v6_timestamp = None
8296
_last_v7_timestamp = None
8397
_last_v8_timestamp = None

test/test_uuid6.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from unittest.mock import patch
44
from uuid import uuid1
55

6-
from uuid6 import UUID, uuid6, uuid7, uuid8
6+
from uuid6 import UUID, uuid6, uuid7, uuid8, uuid1_to_uuid6
77

88
REGEX_UUID6 = r"^[0-9a-f]{8}-[0-9a-f]{4}-6[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
99
REGEX_UUID7 = r"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
@@ -39,6 +39,19 @@ def test_uuid8_generation(self):
3939
self.assertLess(uuid8_1, uuid8_2)
4040
uuid8_1 = uuid8_2
4141

42+
def test_uuid1_to_uuid6_generation(self):
43+
uuid6_1 = None
44+
for _ in range(1000):
45+
uuid_1 = uuid1()
46+
uuid6_2 = uuid1_to_uuid6(uuid_1)
47+
self.assertEqual(uuid6_2.version, 6)
48+
self.assertEqual(uuid6_2.node, uuid_1.node)
49+
self.assertEqual(uuid6_2.clock_seq, uuid_1.clock_seq)
50+
self.assertEqual(uuid6_2.time, uuid_1.time)
51+
if uuid6_1 is not None:
52+
self.assertLess(uuid6_1, uuid6_2)
53+
uuid6_1 = uuid6_2
54+
4255
def test_invalid_int(self):
4356
with self.assertRaises(ValueError):
4457
_ = UUID(int=-1)
@@ -155,6 +168,10 @@ def test_multiple_arguments(self):
155168
with self.assertRaises(TypeError):
156169
_ = UUID(int=0, hex="061d0edc-bea0-75cc-9892-f6295fd7d295")
157170

171+
def test_convert_invalid_version(self):
172+
with self.assertRaises(ValueError):
173+
_ = uuid1_to_uuid6(uuid7())
174+
158175

159176
if __name__ == "__main__":
160177
unittest.main()

test/test_vectors.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import unittest
1111
from unittest.mock import patch
1212

13-
from uuid6 import UUID, uuid6, uuid7, uuid8
13+
from uuid6 import UUID, uuid6, uuid7, uuid8, uuid1_to_uuid6
1414

1515

1616
class TestVectors6(unittest.TestCase):
@@ -56,6 +56,11 @@ def test_uuid6_time_from_hex(self):
5656
uuid_1 = UUID(hex="C232AB00-9414-11EC-B3C8-9E6BDECED846")
5757
self.assertEqual(uuid_6.time, uuid_1.time)
5858

59+
def test_uuid1_to_uuid6(self):
60+
uuid_1 = UUID(hex="C232AB00-9414-11EC-B3C8-9E6BDECED846")
61+
uuid_6 = uuid1_to_uuid6(uuid_1)
62+
self.assertEqual(str(uuid_6), "1ec9414c-232a-6b00-b3c8-9e6bdeced846")
63+
5964

6065
class TestVectors7(unittest.TestCase):
6166
"""

0 commit comments

Comments
 (0)