我遇到了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);
Run Code Online (Sandbox Code Playgroud)
这有效.现在我需要扭转它.
让我教你如何钓鱼,并在此过程中解决你的问题.
我们有什么?
甲DateTime.NET对象,表示一个日期/时间的组合.
DateTime dateTime = new DateTime(2011, 6, 29);
Run Code Online (Sandbox Code Playgroud)我们想要什么?
甲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
Run Code Online (Sandbox Code Playgroud)
请注意,该年份有7位,因此它可以表示从1980年到2107年.除此范围之外的任何内容都无效.由于years是无符号的,因此不能表示负值.但是像1970年(减去1980年)这样的值将是4294967286,因此它也超出了范围.
if (years > 127)
throw new ArgumentOutOfRangeException("Cannot represent the year.");
Run Code Online (Sandbox Code Playgroud)我们如何结合它?
我们需要将所有值移动到结果整数中的适当位置.
以全零整数开始.我们只需要低16位,但为方便起见,我们将在uint这里使用.
uint dosDateTime = 0;
Run Code Online (Sandbox Code Playgroud)
规范列出了每个值开始的位索引.但由于我们忽略了时间部分(16个最低有效位),我们需要从所有这些值中减去16.
天数从第16位开始.我们将它向左移动16到16个位置(即没有移位),我们可以将这些位与结果进行或运算.
dosDateTime |= day << (16 - 16);
Run Code Online (Sandbox Code Playgroud)
月份从第21位(减去16)开始,年份从第25位开始.
dosDateTime |= minutes << (21 - 16);
dosDateTime |= years << (25 - 16);
Run Code Online (Sandbox Code Playgroud)
然后将其转换为无符号的16位整数.它不会溢出.
ushort result = unchecked((ushort)dosDateTime);
Run Code Online (Sandbox Code Playgroud)我们怎么把它放在一起?
将它们放在一起作为扩展方法:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
当然你可以写得更简洁,但这清楚地表明了正在发生的事情.编译器将优化许多常量.
测试它
您应该编写一些单元测试,以确保您的代码正常工作.但是这个快速测试验证了基本的想法:
static void Main(string[] args)
{
DateTime dateTime = new DateTime(2011, 6, 29);
ushort dosDateTime = dateTime.ToDosDateTime();
Console.WriteLine(dosDateTime); // Prints: 16093
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)