67 lines
1.9 KiB
Go
67 lines
1.9 KiB
Go
|
|
package helpers
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"crypto/rand"
|
|||
|
|
"encoding/binary"
|
|||
|
|
"fmt"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
const (
|
|||
|
|
// UUID v7 格式常量.
|
|||
|
|
uuidRandomBytesSize = 10 // UUID中随机字节部分的大小
|
|||
|
|
uuidVersion7 = 0x7000 // UUID v7的版本位
|
|||
|
|
uuidVariant = 0x80 // UUID的变体位
|
|||
|
|
uuidTimeMask = 0xFFFF // 时间戳掩码
|
|||
|
|
uuidTimeShift = 16 // 时间戳位移
|
|||
|
|
uuidVariantMask = 0x3F // 变体掩码
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// NewUUIDv7 生成 UUID v7 并去除连字符.
|
|||
|
|
func NewUUIDv7() string {
|
|||
|
|
// 获取当前时间戳(Unix 毫秒时间戳)
|
|||
|
|
now := time.Now().UnixMilli()
|
|||
|
|
|
|||
|
|
// 生成随机字节
|
|||
|
|
randBytes := make([]byte, uuidRandomBytesSize)
|
|||
|
|
_, err := rand.Read(randBytes)
|
|||
|
|
if err != nil {
|
|||
|
|
// 如果随机数生成失败,使用时间戳加一些伪随机值作为备选方案
|
|||
|
|
return fmt.Sprintf("%016x%016x", now, time.Now().UnixNano())
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 版本和变体位
|
|||
|
|
// 版本: 0x7 (0111) << 12
|
|||
|
|
// 变体: 0x2 (10) << 6
|
|||
|
|
versionVariant := uint16(uuidVersion7 | uuidVariant)
|
|||
|
|
|
|||
|
|
// 构建 UUID 字节数组
|
|||
|
|
var uuid [16]byte
|
|||
|
|
|
|||
|
|
// 时间戳低32位 (4 bytes)
|
|||
|
|
//nolint:gosec // UUID格式要求的类型转换
|
|||
|
|
binary.BigEndian.PutUint32(uuid[0:4], uint32(now>>uuidTimeShift))
|
|||
|
|
|
|||
|
|
// 时间戳中16位 + 版本 (2 bytes)
|
|||
|
|
//nolint:gosec // UUID格式要求的类型转换
|
|||
|
|
binary.BigEndian.PutUint16(uuid[4:6], uint16(now&uuidTimeMask))
|
|||
|
|
|
|||
|
|
// 时间戳高16位 + 变体 (2 bytes)
|
|||
|
|
binary.BigEndian.PutUint16(uuid[6:8], versionVariant)
|
|||
|
|
|
|||
|
|
// 随机数部分 (8 bytes)
|
|||
|
|
copy(uuid[8:16], randBytes[:8])
|
|||
|
|
|
|||
|
|
// 设置变体位 (第8个字节的高两位为10)
|
|||
|
|
uuid[8] = (uuid[8] & uuidVariantMask) | uuidVariant
|
|||
|
|
|
|||
|
|
// 转换为十六进制字符串并去除连字符
|
|||
|
|
return fmt.Sprintf("%08x%04x%04x%04x%08x%04x",
|
|||
|
|
binary.BigEndian.Uint32(uuid[0:4]),
|
|||
|
|
binary.BigEndian.Uint16(uuid[4:6]),
|
|||
|
|
binary.BigEndian.Uint16(uuid[6:8]),
|
|||
|
|
binary.BigEndian.Uint16(uuid[8:10]),
|
|||
|
|
binary.BigEndian.Uint32(uuid[10:14]),
|
|||
|
|
binary.BigEndian.Uint16(uuid[14:16]))
|
|||
|
|
}
|