【问题标题】:Calculating Day, Month, Year计算日、月、年
【发布时间】:2010-09-22 06:28:17
【问题描述】:

如何准确计算日、月、年?

意思..

从 1990 年 1 月 2 日到 2009 年 5 月 9 日是..

xxx 天,xxx 个月,xxx 年。

知道怎么做吗?

我尝试了 Timespan 和 Tick().. 都没有这样做..

【问题讨论】:

  • 你想得到什么:(2008,2,29)->(2009,2,28) 和 (2008,2,28)->(2009,2,28)。我认为 TimeSpan 不支持年和月,因为存在歧义,计算取决于日期差异的定义。

标签: c#


【解决方案1】:

我认为框架中没有内置任何东西可以做到这一点。 TimeSpan 不会这样做,因为天数等取决于确切的起点和终点,而不仅仅是它们之间的持续时间。

这是一种简单的方法,但效率低:

using System;

class Program
{
    static void Main()
    {
        ShowDifference(new DateTime(1990, 1, 2),
                       new DateTime(2009, 5, 9));
    }

    static void ShowDifference(DateTime start,
                               DateTime end)
    {
        if (start > end)
        {
            throw new ArgumentException();
        }
        // See comment at the end
        int years = end.Year - start.Year - 2;
        while (start.AddYears(years) <= end)
        {
            years++;
        }
        years--;
        Console.WriteLine("{0} years", years);
        start = start.AddYears(years);
        int months = 0;
        while (start.AddMonths(months) <= end)
        {
            months++;
        }
        months--;
        Console.WriteLine("{0} months", months);
        start = start.AddMonths(months);
        int days = 0;
        while (start.AddDays(days) <= end)
        {
            days++;
        }
        days--;
        Console.WriteLine("{0} days", days);
    }
}

显然有一些方法可以提高效率,但它们会很繁琐。编辑:我已经改变了这一点,以对年数的一个非常保守的猜测开始 - 它可能比它需要的低一个,但我现在不想考虑极端情况。它肯定可以工作,并且循环都有(相当小)它们运行次数的上限。

请注意,在每个步骤中,您应该将完整的年数/天数/月数添加到起点,而不是一次添加一个月。否则,如果您从 1 月 30 日到 3 月 30 日,它将要求 2 个月和 2 天,因为当您添加一个月时,从 1 月 30 日到 2 月 28 日,然后从 2 月 28 日到 3 月 28 日你增加了第二个月。

希望Noda Time 能够在我最终完成它时让这一切变得更容易:)

【讨论】:

  • 不错的解决方案。但是我认为计算月和日的差异真的很繁琐。这只是为了计算 O(1) 中的年份差异而需要考虑的一种情况,因此该方法本身将在恒定时间内运行。
  • @Makkam:是的,这当然是可行的。这比我现在尝试做对的事情更复杂......
  • @Makkam:我已经用保守的折衷解决方案编辑了代码 - 我怀疑它仍然可以更有效,但我仍然确信它会起作用,而且很简单 :)
  • 它对我有用。 IT 给出了我正在寻找的最准确的结果。为了比较我正在使用这个链接easycalculation.com/date-day/age-calculator.php
  • @PratikGhag:这些天我会使用 Noda Time,这会让事情变得更容易 - 我写这个答案时它没有发布,但从那时起我们已经发布了几个版本 :)
【解决方案2】:

您不能通过直接计算来做到这一点(即TimeSpan 没有“TotalMonths”或“TotalYears”属性,仅仅是因为这些数字对于任意时间间隔没有意义)。

相反,您可以只计算循环中的数字,如下所示:

var dt1 = new DateTime(1990, 1, 2);
var dt2 = new DateTime(2009, 5, 9);

int years = 0;
while (dt1.AddYears(1) < dt2)
{
    years ++;
    dt1 = dt1.AddYears(1);
}

int months = 0;
while (dt1.AddMonths(1) < dt2)
{
    months ++;
    dt1 = dt1.AddMonths(1);
}

int days = (int) Math.Floor(dt2.Subtract(dt1).TotalDays);

我还没有测试过这个,所以可能会有一个错误或其他什么,但这是基本的想法。

【讨论】:

  • 我认为这种“不断添加一个”的方法存在根本问题 - 请参阅我的答案了解详细信息。
  • 我仍然认为我的解决方案更好,并且在O(1) 中运行,除非我忽略了某些东西。
【解决方案3】:

这样的事情怎么样?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DateTimeTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var dt1 = new DateTime(1990, 1, 2);
            var dt2 = new DateTime(2009, 5, 9);

            int days = dt2.Day - dt1.Day;
            int months = dt2.Month - dt1.Month;
            int years = dt2.Year - dt1.Year;

            if (months < 0)
            {
                months += 12;
                years -= 1;
            }
            if (days < 0)
            {
                dt1.AddYears(years);
                dt1.AddMonths(months);
                days = dt2.Subtract(dt1).Days;
                months -= 1;
            }

            Console.WriteLine("{0} Days, {1} Months, {2} Years", days, months, years);
        }
    }
}

输出

7 Days, 4 Months, 19 Years

这是您要寻找的输出吗?您可能需要几个额外的条件,具体取决于您要如何定义“月份”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-19
    • 1970-01-01
    • 2018-04-24
    • 1970-01-01
    • 2014-05-12
    • 1970-01-01
    相关资源
    最近更新 更多