.ET 9 中基于时间的 Guid
.ET 9 中基于时间的 Guid
.ET 9 基于时间创建 Guid
.ET 9 中引入了基于时间来生成 Guid, 因为实现的 RFC 文档里的第七个版本, 所以 API 名称为 Guid.CreateVersion7()
新增的 API 如下:
代码语言:javascript代码运行次数:0运行复制namespace System;
public partial struct Guid
{
public static Guid AllBitsSet { get; }
public int Variant { get; }
public int Version { get; }
public static Guid CreateVersion7();
public static Guid CreateVersion7(DateTimeOffset timestamp);
}
Guid.AllBitsSet
对应着 Guid.Empty
, Empty
的所有比特位都是 0, AllBitsSet
则都是 1
AllBitsSet
Version
和 Variant
代表了当前 Guid 值的实现细节, 可以参考 RFC 文档说明 .html#name-variant-field
Guid.CreateVersion7()
/Guid.CreateVersion7(DateTimeOffset timestamp)
用于创建基于时间的 Guid, 如果没有参数就会使用当前时间
public static Guid CreateVersion7() => CreateVersion7(DateTimeOffset.Utcow);
来看一个使用示例吧,
代码语言:javascript代码运行次数:0运行复制var guid = Guid.CreateVersion7();
Cole.WriteLine(guid.ToString());
Cole.WriteLine($"{nameof(guid.Version)}: {guid.Version}");
Cole.WriteLine($"{nameof(guid.Variant)}: {guid.Variant}");
var timestamp = DateTimeOffset.Utcow;
Cole.WriteLine($"Timestamp: {timestamp} {timestamp.ToUnixTimeMilliseconds()}");
Cole.WriteLine(Guid.CreateVersion7(timestamp));
用起来是不是还挺简单的, 有一个问题, 既然是基于时间的,同一个时间戳会不会生成的 Guid 是一样的呢?
我们来测试一下, 接着前面的示例,
代码语言:javascript代码运行次数:0运行复制guid = Guid.CreateVersion7(timestamp);
Cole.WriteLine(guid);
输出结果如下:
代码语言:javascript代码运行次数:0运行复制0191fa19-7082-7541-ae8e-befcfffe79cb
Version: 7
Variant: 10
Timestamp: 9/16/2024 09:10:56 +00:00 1726477856901
0191fa19-7085-7e0b-ae72-aa6b4585467
0191fa19-7085-782f-a0b-a022baa1
可以看到两次生成的 guid 并不相同, 这从 rfc 文档或者实现细节中可以了解到, 这是因为除了时间参数之外还会有随机参数,导致即使时间一样生成的 guid 还是会不一样
那我们能否从 Guid 中获取到时间呢? 答案是肯定的, 不过获取到的时间不会完全准确有一定的误差, 因为可能会引入随机参数, 从上面的输出也可以看得出来, 两个 guid 的前面十二个字符是完全一样的, 前面 6 个 byte 会是一样的, 他们对应了时间信息, 我们也可以从源码里到一些细节
这里的 _a, _b 对应的就是前面的两段, 也可以从源码的注释里获取更多说明
最后我们可以从 byte 里获取到时间的信息, 实现如下:
代码语言:javascript代码运行次数:0运行复制private static void PrintDateTime(Guid guid)
{
if (guid.Version is not 7)
{
throw new InvalidOperationException("Guid.Version is not 7");
}
var bytes = guid.ToByteArray();
var a = BitConverter.ToInt2(bytes.AsSpan(0, 4));
var b = BitConverter.ToInt16(bytes.AsSpan(4, 2));
var timestamp = (((long)a) << 16) + b;
var dateTime = DateTimeOffset.FromUnixTimeMilliseconds(timestamp);
Cole.WriteLine($"DateTime: {dateTime.UtcDateTime} {timestamp}");
}
接着前面的示例试一下
代码语言:javascript代码运行次数:0运行复制Thread.Sleep(2000);
Cole.WriteLine(Guid.CreateVersion7());
PrintDateTime(guid);
输出结果如下:
可以看到两个时间比较接近但还是会有一些误差,不过误差会比较小,可以看到只有一分钟多一点的误差
Github 上有一个根据 Guid 获取时间的 issue, 不过因为时间并不准确, 可能大概率不会支持, 感兴趣的朋友可以关注
Github issue 上还有作者对于 Guid 实现的一些总结, 感觉可以了解一下, 也分享一下
v1 被广泛认为已过时,应该尽可能用 v7 替代 v2 用于 DCE 安全目的,超出了正常规范 v 被广泛认为已过时,应该尽可能用 v5 替代 v4 用于创建随机 UUID,目前已经通过 支持 v5 用于从字符串输入创建 UUID,但由于使用 SHA-1,因此也被广泛认为已过时,因为存在潜在的安全攻击风险 v6 是简单的 v1,并对位进行了替代排序,同样被广泛认为已过时,应该尽可能用 v7 替代 v7 是本提案通过新的 CreateVersion7 API 所支持的版本 有一些可选的扩展功能尚不支持,但我们可以在未来扩展以支持这些功能 v8 明确用于实验性和特定供应商使用,其包含的位没有定义,仅限于版本和变体字段 这间接地通过普通的新 Guid(...) API 得到支持,这些 API 允许您指定所有底层位的值
v1 被广泛认为已过时,应该尽可能用 v7 替代 v2 用于 DCE 安全目的,超出了正常规范 v 被广泛认为已过时,应该尽可能用 v5 替代 v4 用于创建随机 UUID,目前已经通过 支持 v5 用于从字符串输入创建 UUID,但由于使用 SHA-1,因此也被广泛认为已过时,因为存在潜在的安全攻击风险 v6 是简单的 v1,并对位进行了替代排序,同样被广泛认为已过时,应该尽可能用 v7 替代 v7 是本提案通过新的 CreateVersion7 API 所支持的版本 有一些可选的扩展功能尚不支持,但我们可以在未来扩展以支持这些功能 v8 明确用于实验性和特定供应商使用,其包含的位没有定义,仅限于版本和变体字段 这间接地通过普通的新 Guid(...) API 得到支持,这些 API 允许您指定所有底层位的值
- /
- .html
- .cs
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
下一篇:如何恢复苹果手机置出厂设置
推荐阅读
留言与评论(共有 10 条评论) |
本站网友 挤奶门 | 8分钟前 发表 |
但我们可以在未来扩展以支持这些功能 v8 明确用于实验性和特定供应商使用 | |
本站网友 虬髯客 | 0秒前 发表 |
因为存在潜在的安全攻击风险 v6 是简单的 v1 | |
本站网友 深圳小产权房最新政策 | 30分钟前 发表 |
但我们可以在未来扩展以支持这些功能 v8 明确用于实验性和特定供应商使用 | |
本站网友 凌霄花的功效与作用 | 26分钟前 发表 |
并对位进行了替代排序 | |
本站网友 装修图片库 | 2分钟前 发表 |
这些 API 允许您指定所有底层位的值References/.html.cs本文参与 腾讯云自媒体同步曝光计划 | |
本站网友 阖家安康 | 14分钟前 发表 |
实现如下 | |
本站网友 罗源二手房 | 27分钟前 发表 |
这些 API 允许您指定所有底层位的值v1 被广泛认为已过时 | |
本站网友 教育机构简介 | 26分钟前 发表 |
{timestamp} {timestamp.ToUnixTimeMilliseconds()}"); Cole.WriteLine(Guid.CreateVersion7(timestamp)); 用起来是不是还挺简单的 | |
本站网友 陆东福 | 20分钟前 发表 |
我们也可以从源码里到一些细节这里的 _a |