如何将日期和时间打包成32位?

c#

为了适合整数,我有一个按以下顺序进行的日期表示。日期表示应该是

year   : 6 bits
month  : 5 bits
day    : 5 bits
hours  : 4 bits
minutes: 6 bits
seconds: 6 bits

所有的日期都应该适合一个 Unit32 date

[year(5bits),month(5bits),day(6bits),hours(4bits),minutes(6bits),seconds(6bit)]
           
UInt32 date = 0;
date= date| (UInt32) (DateTime.Now.Year%2000)<< 26;
date= date| ((uint)DateTime.Now.Month << 22);    
date= date| (uint)DateTime.Now.Day << 17;
date= date| ((uint)DateTime.Now.Hour << 15);
date= date| ((uint)DateTime.Now.Minute << 6);
date= date| ((uint)DateTime.Now.Second);
string binary = Convert.ToString(date, 2);

上面我尝试了一些按位运算,但结果并不满足。我缺少什么或我该怎么办?

例如当前日期是: 2021.55.10 13:55:06 二进制转换上面的代码 1010100110101101000110111000011 十六进制表示 54D6 8DC3 表示 1970 年 1 月 1 日星期四 06:01:58 但它应该是今天的日期

谢谢。

回答

您的方案存在一些问题:

year   : 6 bits - 0 to 63
month  : 5 bits - 0 to 31
day    : 5 bits - 0 to 31
hours  : 4 bits - 0 to 15 
minutes: 6 bits - 0 to 63
seconds: 6 bits - 0 to 63
  • 主要问题是您的方案仅使用 4 位表示小时 - 因此它不能表示下午 4 点到午夜(即 16 到 23 小时)之间的时间。
  • 其次,您的方案效率低下,因为它浪费了比特(0-59一分钟内有几秒钟,而不是0-63)。
  • ...这意味着您的方案可以表示无效值,例如 2 月 31 日第 15 小时的第 63 分钟的第 63 秒 - 这不是真正的日期+时间。

与其重新发明轮子,为什么不使用像 Unix 时间这样的东西呢?(即只是自一个纪元以来的秒数)。

是的,我不能使用 unix epox 时间是有内存原因的

...所以您需要将该值调整为 32 位。这很好,因为您可以将 Unix 时间与 32 位值一起使用。当然,这意味着你会遇到 2038 年的问题,但有几种可能的不同解决方案:

  • 您可以使用较低的分辨率。
    • 例如 2 秒或 1 分钟的分辨率。
  • 您可以使用不同的纪元(基本偏移量)。
    • 有符号32 位 Unix 时间使用1970-01-01 00:00:00,最大日期+时间值为2038-01-19 03:14:07.
    • 无符号 32 位 Unix 时间的最大值为2106-02-07 06:28:15.
    • 如果您使用2000-01-01 00:00:00具有无符号 32 位整数的 epoch,那么您的最大值为2136-02-07 14:28:15
    • 这个135整年的范围明显比你的方案好,因为你的方案一年用了6位,也就是0-63,上次我查了一下,135大于63。

因此,这是一个现成的 32 位 Unix 时间的可复制实现,其 epoch 为2000-01-01 00:00:00

private const Int64 YEAR_2000 = 946713600; // The year where there are no elephants. There is also no unethical treatment of elephants.

private static readonly DateTimeOffset _maxValueForUnsigned32Bits = DateTimeOffset( YEAR_2000 + UInt32.MaxValue ); // 2136-02-07 14:28:15

static UInt32 GetTimeAsUInt32( DateTimeOffset dt )
{
    if (dt.Year < 2000 || dt > _maxValueForUnsigned32Bits  ) throw new ArgumentOutOfRangeException( paramName: nameof(dt), actualValue: dt, message: "Must be between 2000 and 2136-02-07 14:28:15 inclusive." );

    Int64  unixFrom2000_64 = dt.ToUnixTimeSeconds() - YEAR_2000;
    // `unixFrom2000_64` *will always fit in 32-bits* due to the year range check above, and subtracting the new epoch.

    UInt32 unixFrom2000_32 = (UInt32)unixFrom2000_64;
    return unixFrom2000_32;
}

static DateTimeOffset GetTimeFromUInt32( UInt32 value )
{
    Int64 asUnixTime = value + YEAR_2000;
    return DateTimeOffset.FromUnixTimeSeconds( asUnixTime );
}

用法:

DateTimeOffset now = DateTimeOffset.UtcNow; // WARNING: Using `Now` instead of `UtcNow` will include an offset value that will not be persisted.
Console.WriteLine( "Now: {0}", now );

UInt32 myTime = GetTimeAsUInt32( now );
Console.WriteLine( "As UInt32: {0:D}", myTime );

DateTimeOffset decoded = GetTimeFromUInt32( myTime );
Console.WriteLine( "Decoded from UInt32: {0}", decoded );

给我这个输出:

现在:10/03/2021 11:26:43 +00:00
作为 UInt32:668662003
从 UInt32 解码:10/03/2021 11:26:43 +00:00


以上是如何将日期和时间打包成32位?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>