将日期转换为DOS日期

时间:2013-04-01 13:43:10

标签: c# datetime dos

我遇到了DOS日期格式的问题。我需要转换:

From:
       29th June of 2011 
To:
       16093

我知道16093是正确的结果,但我怎样才能得到这个结果?


我可以将DOS日期整数值转换为已识别的DateTime,但不知道如何反转该过程。这是我从DOS日期到DateTime的转换方式:

var number = 16093;

var year = (number >> 9) + 1980;
var month = (number & 0x01e0) >> 5;
var day = number & 0x1F;
var date = new DateTime((int)year, (int)month, (int)day);

这很有效。现在我需要扭转它。

3 个答案:

答案 0 :(得分:6)

让我教你如何钓鱼,并在此过程中解决你的问题。

  1. 我们有什么?

    表示日期/时间组合的DateTime .NET对象。

    DateTime dateTime = new DateTime(2011, 6, 29);
    
  2. 我们想要什么?

    根据规范的DOS date/time,但仅限于16位日期组件。时间组件被忽略。

  3. 我们需要什么?

    自1980年以来的月份,月份编号和年份。让我们将它们作为无符号整数,并确保它们处于适当的范围内。

    uint day = (uint)dateTime.Day;              // Between 1 and 31
    uint month = (uint)dateTime.Month;          // Between 1 and 12
    uint years = (uint)(dateTime.Year - 1980);  // From 1980
    

    请注意,该年份有7位,因此它可以表示从1980年到2107年。除此范围之外的任何内容都无效。由于years是无符号的,因此无法表示负值。但是像1970年(减去1980年)那样的值将是4294967286,因此它也超出了范围。

    if (years > 127)
        throw new ArgumentOutOfRangeException("Cannot represent the year.");
    
  4. 我们如何结合它?

    我们需要将所有值移动到结果整数中的适当位置。

    以全零整数开始。我们只需要低16位,但为方便起见,我们在这里使用uint

    uint dosDateTime = 0;
    

    规范列出了每个值开始的位索引。但由于我们忽略了时间部分(16个最低有效位),我们需要从所有这些值中减去16个。

    天数从第16位开始。我们将它向左移动16到16个位置(即没有移位),我们可以将这些位与结果进行或运算。

    dosDateTime |= day << (16 - 16);
    

    月份从第21位(减去16)开始,年份从第25位开始。

    dosDateTime |= minutes << (21 - 16);
    dosDateTime |= years << (25 - 16);
    

    然后将其转换为无符号的16位整数。它不会溢出。

    ushort result = unchecked((ushort)dosDateTime);
    
  5. 我们如何将它组合在一起?

    将所有内容放在一起作为扩展方法:

    public static class DateTimeExtensions
    {
        public static ushort ToDosDateTime(this DateTime dateTime)
        {
            uint day = (uint)dateTime.Day;              // Between 1 and 31
            uint month = (uint)dateTime.Month;          // Between 1 and 12
            uint years = (uint)(dateTime.Year - 1980);  // From 1980
    
            if (years > 127)
                throw new ArgumentOutOfRangeException("Cannot represent the year.");
    
            uint dosDateTime = 0;
            dosDateTime |= day << (16 - 16);
            dosDateTime |= month << (21 - 16);
            dosDateTime |= years << (25 - 16);
    
            return unchecked((ushort)dosDateTime);
        }
    }
    

    当然你可以写得更简洁,但这清楚地表明了正在发生的事情。编译器将优化许多常量。

  6. 测试

    您应该编写一些单元测试,以确保您的代码正常工作。但是这个快速测试验证了基本的想法:

    static void Main(string[] args)
    {
        DateTime dateTime = new DateTime(2011, 6, 29);
        ushort dosDateTime = dateTime.ToDosDateTime();
        Console.WriteLine(dosDateTime);     // Prints: 16093
        Console.ReadLine();
    }
    

答案 1 :(得分:1)

看起来不像.Net框架只包含一种方法,但是knowing the dos time format,有些位移,你可以编写自己的转换器。

答案 2 :(得分:0)

这应该可行:

private static DateTime DosDateToDateTime(ushort dosdate)
{
    return new DateTime((dosdate >> 9) + 1980, (dosdate >> 5) & 0xF, dosdate & 0x1F);
}