0

我在使用 DOS 日期格式时遇到问题。我需要转换:

从:
       2011 年 6 月 29 日
到:
       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);

这行得通。现在我需要扭转它。

4

3 回答 3

8

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

  1. 我们有什么?

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

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

    符合规范的DOS 日期/时间,但仅限于 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此处使用 an。

     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();
     }
    
于 2013-04-01T14:13:08.603 回答
2

看起来 .Net 框架不包含仅用于此目的的方法,但知道 dos 时间格式,通过一些位移,您可以编写自己的转换器。

于 2013-04-01T13:46:23.587 回答
0

这应该可以正常工作:

private static DateTime DosDateToDateTime(ushort dosdate)
{
    return new DateTime((dosdate >> 9) + 1980, (dosdate >> 5) & 0xF, dosdate & 0x1F);
}
于 2013-04-01T14:12:36.237 回答