UUIDv7 in Perl

I came across UUIDv7 in 20 languages, a blog post about UUIDv7. I talked about the new UUIDs a couple of years ago. Since then, they have been approved. This post generates one of them in 20 different languages. I noticed Perl wasn't among them, so I wrote it.

#!/usr/bin/env perl

use v5.40;
use Time::HiRes;

my $value;

# Start with 48 bits of the current time in ms
my $milliseconds = int(Time::HiRes::time * 1000);
vec($value, 0, 32) = $milliseconds >> 16;
vec($value, 2, 16) = $milliseconds;

# Add 80 bits of random
vec($value, $_ + 6, 8) = int(rand(256)) for 0..9;

# Replace version bits with 7.
vec($value, 13, 4) = 7;

# Replace "var" bits with 0b10.
vec($value, 35, 2) = 2;

# Print with dashes, like this
# 0190163d-8694-739b-aea5-966c26f8ad91
my $s = unpack 'H*', $value;
substr($s, $_, 0, '-') for (8, 13, 18, 23);
say $s;

But the article implies that rand isn't random enough, so I wrote it with urandom

#!/usr/bin/env perl

use v5.40;
use Crypt::URandom;
use Time::HiRes;

# 128 bits (16 bytes) random
my $value = Crypt::URandom::urandom(16);

# Replace first 48 bits with current time in ms
my $milliseconds = int(Time::HiRes::time * 1000);
vec($value, 0, 32) = $milliseconds >> 16;
vec($value, 2, 16) = $milliseconds;

# Replace version bits with 7.
vec($value, 13, 4) = 7;

# Replace "var" bits with 0b10.
vec($value, 35, 2) = 2;

# Print with dashes, like this
# 0190163d-8694-739b-aea5-966c26f8ad91
my $s = unpack 'H*', $value;
substr($s, $_, 0, '-') for (8, 13, 18, 23);
say $s;

But Crypt::URandom is on CPAN, not in the standard library. If we were willing to add a CPAN dependency, we might as well add UUID!

❯ perl -MUUID=uuid7 -E 'say uuid7'
0190274d-abb5-7cdf-8bd7-483dbdd79906

So I didn't contribute a Perl solution to UUIDv7 in N languages.