繁体   English   中英

System.DateTime种类比特

[英]System.DateTime Kind Bits

由于我遇到尝试调用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()方法的输出都不同?

我希望任何能够指出我能够帮助我了解我出错的资源方向的信息。

这些多头都是不同的,再次如预期的那样。 然而,我接着试图“检查”上面两位以查看哪个状态对应于什么设置,并发现上面两位在所有三个中都设置相同。

我真的不认为是这种情况 - 不是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;
}

最后,我做了一些阅读并发现(或者至少在一个来源中说过)MS没有在.ToBinary()中序列化Kind信息。

很容易证明这不是真的:

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("===");
    }
}

ToBinary()对不同的DateTimeKind工作方式不同。 你可以在.NET源代码上看到它:

public Int64 ToBinary() {
    if (Kind == DateTimeKind.Local) {
        // Local times need to be adjusted as you move from one time zone to another, 
        // just as they are when serializing in text. As such the format for local times
        // changes to store the ticks of the UTC time, but with flags that look like a 
        // local date.

        // To match serialization in text we need to be able to handle cases where
        // the UTC value would be out of range. Unused parts of the ticks range are
        // used for this, so that values just past max value are stored just past the
        // end of the maximum range, and values just below minimum value are stored
        // at the end of the ticks area, just below 2^62.
        TimeSpan offset = TimeZoneInfo.GetLocalUtcOffset(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
        Int64 ticks = Ticks;
        Int64 storedTicks = ticks - offset.Ticks;
        if (storedTicks < 0) {
            storedTicks = TicksCeiling + storedTicks;
        }
        return storedTicks | (unchecked((Int64) LocalMask));
    }
    else {
        return (Int64)dateData;
    }
}  

这就是为什么你得到不同的位 - 在转换成位之前调整本地时间,因此它不再匹配utc时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM