将Double转换为DateTime?

11
我有一个.CSV文件,正在将其读入C#程序。其中一列中有一个日期,但它以“通用”格式显示,因此在CSV文件中显示为数字。例如:41172。
如何在C#中将此数字转换为格式为dd/mm/yyyy的日期? 41172等同于20/09/2012。

我同意在asp.net中没有这样的日期格式!它只是一个随机数!你应该尝试将有效日期导出到CSV文件。创建CSV文件的程序是什么? - Haris
4
DateTime.FromOADate(41172) 对你有用吗? - dash
5个回答

34
要将“Excel格式”中的DateTime转换为C# DateTime,您可以使用DateTime.FromOADate函数。
在上面的示例中:
   DateTime myDate = DateTime.FromOADate(41172);

为了以所需格式显示它,请使用以下内容:
   myDate.ToString("dd/MM/yyyy");

如果你想知道Excel日期处理中的差异来自哪里,那是有意为之的:

当Lotus 1-2-3首次发布时,该程序假定1900年是闰年,即使实际上它不是闰年。这使得程序更容易处理闰年,并对几乎所有Lotus 1-2-3中的日期计算没有造成任何影响。

当Microsoft Multiplan和Microsoft Excel发布时,它们也假定1900年是闰年。这使得Microsoft Multiplan和Microsoft Excel可以使用与Lotus 1-2-3相同的序列日期系统,并提供更大的兼容性。将1900年视为闰年也使用户更容易从一个程序移动工作表到另一个程序。

尽管在技术上可以纠正此行为,以便当前版本的Microsoft Excel不假定1900年是闰年,但这样做的缺点大于优点。

来源:http://www.ozgrid.com/Excel/ExcelDateandTimes.htm


1
这是关于同样怪癖的另一个有趣轶事:http://www.joelonsoftware.com/items/2006/06/16.html - CrazyPyro

15

编辑:正如评论和其他答案中所提到的,DateTime.FromOADate 是一个更好的方法。如果有人取消接受此答案,我将删除它。(但是,在像.NET Core这样仍不支持FromOADate的平台上,它仍然对使用这些平台的人很有用。)

我猜你想要:

DateTime date = new DateTime(1900, 1, 1).AddDays(days - 2);

(参见其他答案,了解为什么需要减去2.)


4
该函数的参数是一个日期数字,表示自1899年12月30日午夜以来的天数,可正可负。该函数将此数字转换为等效的日期和时间。 - Richard
1
而传言是:因为1900年不是闰年,但有人忘了。 - H H
看起来很一致,所以我可以减去2。非常感谢。 - Paul
@dash:它是如何进入Lotus的? - H H
1
@Paul:如果您取消接受此答案并接受其他答案(例如dash的答案),我将删除此答案。 - Jon Skeet
显示剩余2条评论

3

如果你正在寻找.Net Core中的FromOADate,那么它并不存在。

我对.Net Framework进行了反汇编,并创建了一个扩展方法。

        public static DateTime FromOADate(this double date)
        {
            return new DateTime(DoubleDateToTicks(date), DateTimeKind.Unspecified);
        }

        internal static long DoubleDateToTicks(double value)
        {
            if (value >= 2958466.0 || value <= -657435.0)
                throw new ArgumentException("Not a valid value");
            long num1 = (long)(value * 86400000.0 + (value >= 0.0 ? 0.5 : -0.5));
            if (num1 < 0L)
                num1 -= num1 % 86400000L * 2L;
            long num2 = num1 + 59926435200000L;
            if (num2 < 0L || num2 >= 315537897600000L)
                throw new ArgumentException("Not a valid value");
            return num2 * 10000L;
        }

仍需要对其进行测试。


2
Excel使用的日期格式虽然过时,但仍然被DateTime.FromOADate函数支持。您可以使用该函数将数字转换为日期。它的定义如下:从1899年12月30日午夜开始计算的天数。

-1

我在 MSDN 上看到了这个链接:http://msdn.microsoft.com/en-us/library/system.datetime.fromoadate.aspx,但我认为它是错误的。

真正的问题是 Excel 错误地认为世纪年(1900)是闰年,而实际上不是,但 2000 年是!

要检查这一点,请将 Excel 中的单元格格式设置为日期,然后输入 1,它会显示 1900 年 1 月 1 日。现在输入 59,它会显示 1900 年 2 月 28 日60 显示 1900 年 2 月 29 日(不是真实日期),然后 61 显示 1900 年 3 月 1 日

所以...

switch (days)
{
   case < 1:
     // Not valid. Do whatever...
   break;
   case < 59:
     DateTime date = new DateTime(1900, 1, 1).AddDays(days);
   break;
   default:
     // Knock off the extra days caused by 29 Feb 1900 and 29 Feb 2000
     DateTime date = new DateTime(1900, 1, 1).AddDays(days-2);
   break;
}

2000年是一个闰年。就像1600和2400一样。所以你只对1900年正确。 - H H
@Henk:谢谢!我知道这个,但不知怎么忘了。哈哈,我真是个白痴!我会编辑我的回答... - Tom Chantler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接