c# - System.DateTime 种类位

标签 c# .net datetime

由于在尝试调用 DotNetOAuth CryptoKey 构造函数时遇到困难,我开始研究 .Net System.DateTime 结构。根据我读到的内容,这个对象实际上由一个 64 位有符号整数表示,“Ticks”在低 62 位编码,Kind 在高 2 位编码(IOW,它是 2 位的串联种类和 62 位刻度)。

现在我想真正“看到”这个,所以我构建了一个小的 C# 程序,它创建了三个 System.DateTime 对象,如下所示:

    DateTime dtUtc = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Utc);
    DateTime dtLocal = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Local);
    DateTime dtU = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Unspecified);

然后我转储了每个的 ticks 属性,正如预期的那样,它们都是相等的。最后,我应用了 .ToBinary()

    long bitUtc = dtUtc.ToBinary();
    long bitLocal = dtLocal.ToBinary();
    long bitU = dtU.ToBinary();

这些多头都是不同的,同样符合预期。然而,然后我尝试“检查”高两位以查看哪个状态对应于什么设置,并发现高两位在所有三个中都设置相同。我使用以下例程返回位状态:

public static bool IsBitSet<T>(this T t, int pos) where T : struct, IConvertible
{
    var value = t.ToInt64(CultureInfo.CurrentCulture);
    return (value & (1 << pos)) != 0;
}

(我从关于 SO 的另一篇文章中得到这个),并这样调用它:

    Boolean firstUtc = Class1.IsBitSet<long>(bitUtc, 63);
    Boolean secondUtc = Class1.IsBitSet<long>(bitUtc, 62);
    Boolean firstLocal = Class1.IsBitSet<long>(bitLocal, 63);
    Boolean secondLocal = Class1.IsBitSet<long>(bitLocal, 62);
    Boolean firstU = Class1.IsBitSet<long>(bitU, 63);
    Boolean secondU = Class1.IsBitSet<long>(bitU, 62);

同样,所有三个中的第一位和第二位都设置为相同(第一个为真,第二个为假)。我不明白这一点,因为我认为这些都会不同,对应于不同的 SystemKind 值。

最后,我做了更多阅读并发现(或者至少在一个来源中是这样说的)MS 没有序列化 .ToBinary() 中的 Kind 信息。好的,但是为什么 .ToBinary() 方法的输出完全不同?

如果有人能为我指明资源方向,帮助我了解哪里出了问题,我将不胜感激。

最佳答案

These longs were all different, again as expected. HOWEVER, I then tried to "inspect" the upper two bits to see which state corresponded to what settings, and found that the upper two bits were set the same in all three.

我真的不认为是这种情况 - ToBinary 的结果不是这样。这是一个简短但完整的程序,它使用您的源数据展示了差异,并将结果显示为十六进制(就像未签名一样):

using System;

class Test
{
    static void Main()
    {
        DateTime dtUtc = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Utc);
        DateTime dtLocal = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Local);
        DateTime dtU = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Unspecified);
        Console.WriteLine(dtUtc.ToBinary().ToString("X16"));
        Console.WriteLine(dtLocal.ToBinary().ToString("X16"));
        Console.WriteLine(dtU.ToBinary().ToString("X16"));
    }
}

输出:

48D131A200924700
88D131999ECDDF00
08D131A200924700

前两位追溯为 01、10 和 00。根据 Marcin 的帖子,其他位也会根据本地情况发生变化 - 但前两位确实表示类型。

IsBitSet 方法被破坏了,因为它左移了一个 int 文字而不是一个 long 文字。这意味着转变将是 mod 32,而不是预期的 mod 64。试试这个:

public static bool IsBitSet<T>(this T t, int pos) where T : struct, IConvertible
{
    var value = t.ToInt64(CultureInfo.CurrentCulture);
    return (value & (1L << pos)) != 0;
}

Finally, I did some more reading and found (or at least it was said in one source) that MS doesn't serialize the Kind information in .ToBinary().

证明这不是真的很容易:

using System;

class Test
{
    static void Main()
    {
        DateTime start = DateTime.UtcNow;
        Show(DateTime.SpecifyKind(start, DateTimeKind.Utc));
        Show(DateTime.SpecifyKind(start, DateTimeKind.Local));
        Show(DateTime.SpecifyKind(start, DateTimeKind.Unspecified));
    }

    static void Show(DateTime dt)
    {
        Console.WriteLine(dt.Kind);
        DateTime dt2 = DateTime.FromBinary(dt.ToBinary());
        Console.WriteLine(dt2.Kind);
        Console.WriteLine("===");
    }
}

关于c# - System.DateTime 种类位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23396706/

相关文章:

c# - 获取当前正在访问的 "row"中的Repeater Label

c# - 使用 PostAsJsonAsync C# 时出现错误请求

.net - 日期的 Math.Min 和 Math.Max 等效吗?

php - 如何使用 PHP-CLI 提示输入并将输入作为变量提供?

python - 错误 "ValueError: can' t 格式日期这么早"在一台 PC 上,在其他 PC 上工作

c# - 如何在 C# 中获得与在 PHP 单元测试中相同的 HMAC256 结果?

c# - 用户名上的 SharePoint 表单例份验证提供程序名称前缀

c# - 美化从 C# 代码块中剥离泛型

c# - C# 2.0 中的接口(interface)多态性

c# - 系统参数异常 mvc .net