【问题标题】:Converting Double to DateTime?将 Double 转换为 DateTime?
【发布时间】:2017-04-26 14:49:57
【问题描述】:

我有一个 .CSV 文件,我正在将其读入 C# 程序。在其中一列中,有一个日期,但它是“一般”格式,因此它在 .CSV 中显示为一个数字。例如:41172。

如何在 C# 中将此数字转换为 dd/mm/yyyy 格式的日期? 41172 相当于 20/09/2012。

【问题讨论】:

  • 我同意我所知道的 asp.net 中没有这样的日期格式!它只是一个随机数!您应该尝试将有效日期导出到 CSV 文件。什么程序正在创建 CSV 文件?
  • DateTime.FromOADate(41172) 是否适合您?

标签: c# excel datetime datetime-format


【解决方案1】:

要从“Excel 格式”的 DateTime 转换为 C# Date Time,您可以使用 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 并提供与 Lotus 1-2-3 的更大兼容性。治疗 1900 年作为闰年也使用户更容易移动工作表 从一个程序到另一个程序。

尽管在技术上可以纠正这种行为,以便 当前版本的 Microsoft Excel 并不认为 1900 是一个飞跃 年,这样做的弊大于利。

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

【讨论】:

【解决方案2】:

编辑:如 cmets 和其他答案所述,DateTime.FromOADate 是一种更好的方法。如果它不被接受,我会删除这个答案。 (但是,像 .NET Core 这样的平台仍然不支持 FromOADate,因此对于使用这些平台的人来说仍然有用。)

我怀疑你想要:

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

(请参阅其他答案,了解为什么需要减去 2。)

【讨论】:

  • msdn.microsoft.com/en-us/library/… - “基准日期,1899 年 12 月 30 日午夜之前或之后的天数”
  • 谣言是:因为 1900 年不是闰年,但有人忘记了。
  • 它似乎是一致的,所以我可以减去 2。非常感谢。
  • @HenkHolterman 我听说的故事是保持与最初有这个错误的 Lotus 1-2-3 的兼容性。
  • @Paul:如果您不接受此答案以接受另一个答案(例如破折号),我将删除此答案。
【解决方案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;
        }

还需要测试一下。

【讨论】:

    【解决方案4】:

    Excel 使用的日期格式较旧,但仍受 DateTime.FromOADate 函数支持,您可以使用该函数转换此数字。它被定义为

    基准日期(12 月 30 日午夜)之前或之后的天数 1899

    【讨论】:

      【解决方案5】:

      我从 MSDN 看到这个:http://msdn.microsoft.com/en-us/library/system.datetime.fromoadate.aspx,但我实际上认为这是错误的。

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

      要检查这一点,请尝试在 Excel 中将单元格格式化为日期,然后输入 1 并给出 1 Jan 1900。现在输入59,它会给出28 Feb 190060 给出29 Feb 1900(不是真实日期),然后61 给出01 March 1900

      所以...

      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 左右是对的。
      • @Henk:谢谢!我确实知道这一点,但不知何故忘记了。大声笑,我是个白痴!我将编辑我的答案...
      猜你喜欢
      • 2021-07-25
      • 2014-05-06
      • 2020-02-02
      • 2023-04-01
      • 2016-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多