C# 如何将日期和时间打包为32位?

C# 如何将日期和时间打包为32位?,c#,bitwise-operators,C#,Bitwise Operators,为了符合int,我有以下顺序的日期重新植入。日期重新植入应为 year : 6 bits month : 5 bits day : 5 bits hours : 4 bits minutes: 6 bits seconds: 6 bits 所有日期都应适合Unit32日期 [year(5bits),month(5bits),day(6bits),hours(4bits),minutes(6bits),seconds(6bit)] UInt32 date =

为了符合int,我有以下顺序的日期重新植入。日期重新植入应为

year   : 6 bits
month  : 5 bits
day    : 5 bits
hours  : 4 bits
minutes: 6 bits
seconds: 6 bits
所有日期都应适合
Unit32日期

[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);
[年(5位)、月(5位)、日(6位)、时(4位)、分(6位)、秒(6位)]
UInt32日期=0;

date=date |(UInt32)(DateTime.Now.Year%2000)您的方案存在一些问题:

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位。这很好,因为可以使用带有32位值的Unix时间。当然,这意味着有几种可能的不同解决方案:

  • 您可以使用较低的分辨率。
    • e、 g.2秒或1分钟的分辨率
  • 可以使用不同的历元(基准偏移)。
    • 已签名32位Unix时间使用最大日期+时间值为
      2038-01-19 03:14:07的
      1970-01-01 00:00:00
    • 无符号32位Unix时间的最大值为
      2106-02-07 06:28:15
    • 如果将
      2000-01-01 00:00:00
      的历元与无符号32位整数一起使用,则最大值为
      2136-02-07 14:28:15
    • 135整年的范围比您的方案好得多,因为您的方案使用6位作为年份,即0-63,上次我检查时,135大于63
下面是一个32位Unix时间的现成拷贝“n”实现,其纪元为
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 );
}
给我这个输出:

现在:2021年3月10日11:26:43+00:00
同于UInt32:668662003
从UInt32:10/03/2021 11:26:43+00:00解码


“结果并不令人满意。”这并不是对您遇到的问题的最清晰的描述。您使用的移位常量看起来也不正确(尤其是小时15和17,月22和26),因为您使用的是
DateTime。现在,在每一行上,如果时间在计算过程中逐渐变为新的小时/分钟/天,那么您可能会得到一些非常奇怪的数字。您不应该使用
DateTime。现在
以相同的方法重复使用-您需要先在变量中存储快照值,这是因为
DateTime.Now
可以在调用之间更改(例如,如果您的代码开始于
23:59:59.999
但结束于
00:00:00.001
。4位代表0到23之间的值?祝您好运!@canton7已修复,谢谢。
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 );