将日期转换为DOS日期
本文关键字:日期 DOS 转换 | 更新日期: 2023-09-27 18:06:44
我在使用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);
这工作。现在我需要反转它
让我教你如何钓鱼,并在此过程中解决你的问题。
-
我们有什么?
表示日期/时间组合的
DateTime
. net对象。DateTime dateTime = new DateTime(2011, 6, 29);
-
我们想要什么?
根据规范的DOS日期/时间,但只具有16位日期组件。时间分量被忽略。
-
我们需要什么?
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.");
-
我们如何结合?
我们需要将所有值移到生成的整数中相应的位置。
从全零整数开始。我们只需要较低的16位,但为了方便,我们在这里使用
uint
。uint dosDateTime = 0;
规范列出了每个值起始位置的位索引。但是由于我们忽略了时间部分(16位最低有效位),我们需要从所有这些值中减去16。
天从16位开始。我们将其向左移动16 - 16位(即不移动),我们可以将这些位与结果进行OR运算。
dosDateTime |= day << (16 - 16);
月从第21位(- 16)开始,年从第25位开始。
dosDateTime |= minutes << (21 - 16); dosDateTime |= years << (25 - 16);
然后将其转换为无符号16位整数。它不会溢出。
ushort result = unchecked((ushort)dosDateTime);
-
我们如何把它们放在一起?
把所有这些放在一起作为一个扩展方法:
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); } }
当然你可以写得更简洁,但这清楚地显示了发生了什么。编译器将优化许多常量。
-
测试
你应该写一些单元测试来检查你的代码是否正常工作。但是这个快速测试验证了基本思想:
static void Main(string[] args) { DateTime dateTime = new DateTime(2011, 6, 29); ushort dosDateTime = dateTime.ToDosDateTime(); Console.WriteLine(dosDateTime); // Prints: 16093 Console.ReadLine(); }
看起来不像。net框架包含这样的方法,但是知道dos时间格式,通过一些位移位,您可以编写自己的转换器。
这应该可以正常工作:
private static DateTime DosDateToDateTime(ushort dosdate)
{
return new DateTime((dosdate >> 9) + 1980, (dosdate >> 5) & 0xF, dosdate & 0x1F);
}