使用C#计算年份差异

106

我该如何计算两个日期之间的年份差异?

例如:(Datetime.Now.Today() - 11/03/2007) 的年份差异。


1
你标记为答案的代码实际上是错误的。它可能会返回不正确的结果。 - Mick
18个回答

147

我编写了一个实现,可以准确处理相隔一年的日期。

但是,与另一个算法不同,它不能优雅地处理负时间间隔。它也没有使用自己的日期算术,而是依赖于标准库。

因此,在此展示代码:

DateTime zeroTime = new DateTime(1, 1, 1);

DateTime a = new DateTime(2007, 1, 1);
DateTime b = new DateTime(2008, 1, 1);

TimeSpan span = b - a;
// Because we start at year 1 for the Gregorian
// calendar, we must subtract a year here.
int years = (zeroTime + span).Year - 1;

// 1, where my other algorithm resulted in 0.
Console.WriteLine("Yrs elapsed: " + years);

9
这处理了平均闰年,但每年最多会偏差一小时十八次。 - Ben Voigt
7
使用这种方法,1/1/2007和1/1/2008之间的差异将为0年。直觉上,应该是1年。 - o. nate
4
好主意,虽然我不知道其他有效的方法……也许可以增加一天? - Richard J. Ross III
6
今天(12/31)对我们来说出了一些问题。加法计算导致了一个偏移一天的问题,当12/31日期与1/1相比较时。我们通过首先从时间跨度中减去一天来解决这个问题。 - dotjosh
4
这个问题的正确答案很可能是这个,但如果你希望每次都能得到正确的答案,那么这个答案是不准确的。这是因为闰年的存在,起始日期很重要! - Mick
显示剩余2条评论

67

使用:

int Years(DateTime start, DateTime end)
{
    return (end.Year - start.Year - 1) +
        (((end.Month > start.Month) ||
        ((end.Month == start.Month) && (end.Day >= start.Day))) ? 1 : 0);
}

2
这句话的意思是,2008年11月2日比2007年11月3日晚一年,但大多数人会说它少了一天。 - Ben Voigt
你是对的。我已经更新了我的代码,严格按照年、月和日属性来计算。现在它看起来有点难看,但可以处理闰年。 - dana
1
我知道这是一个老答案,但只想补充一下,可以通过比较DayOfYear属性来简化,而不是将月份和年份一起比较。 - Tarec
1
@Tarec - 我的第一次修改使用了 DayOfYear 属性... 但是由于 @BenVoigt 的评论,我做出了改变。 - dana

28

我们需要编写一个检查来确定两个日期之间的差异,即开始和结束日期是否大于2年。

感谢上面的提示,以下是完成的代码:

 DateTime StartDate = Convert.ToDateTime("01/01/2012");
 DateTime EndDate = Convert.ToDateTime("01/01/2014");
 DateTime TwoYears = StartDate.AddYears(2);

 if EndDate > TwoYears .....

8
简化版:如果(生日.添加年份(18)>当前协调世界时日期)//未满18岁 - Code Slinger
如果你从StartDate.AddYears(2)减去1天,而不是使用DateTime TwoYears = StartDate.AddYears(2),那么你将得到更精确的答案...我不知道这取决于需求。 - Renascent

21
如果您只是出于琐碎原因需要知道某人的年龄,则使用 Timespan 可行,但如果您需要计算退休金、长期存款或任何与财务、科学或法律有关的事情,则恐怕 Timespan 不够准确,因为 Timespan 假设每年都有相同数量的天数、小时和秒数。

实际上,一些年份的长度会发生变化(出于本回答范围之外的不同原因)。要解决 Timespan 的限制,您可以模仿 Excel 的做法:

    public int GetDifferenceInYears(DateTime startDate, DateTime endDate)
    {
        //Excel documentation says "COMPLETE calendar years in between dates"
        int years = endDate.Year - startDate.Year;

        if (startDate.Month == endDate.Month &&// if the start month and the end month are the same
            endDate.Day < startDate.Day// AND the end day is less than the start day
            || endDate.Month < startDate.Month)// OR if the end month is less than the start month
        {
            years--;
        }

        return years;
    }

1
我一直在使用这段老代码,但最近遇到了闰年问题。客户报告说显示的时间差为3年,实际上只有2年。原来是因为2月29日被四舍五入成2月28日,导致与人类预期相比少了一年。 - Whelkaholism
这个代码会将年份X的2月29日和年份Y的2月28日之间的差异计算为1年。我不确定是否有关于这个问题的规定,快速搜索也没有找到相关信息。 - undefined

13
var totalYears = 
    (DateTime.Today - new DateTime(2007, 03, 11)).TotalDays
    / 365.2425;

维基百科/闰年中获取的平均天数。


8
平均而言是正确的,但并非总是如此。 - Mick
@Mick,你能否解释一下在什么具体情况下会出错吗?谢谢。 - Nam Le
3
@NamLe,一年的天数要么是365天,要么是366天(闰年),它永远不会是365.2425天。 因此,该公式仅能近似正确。 - Mick
这并不完全正确。这个“近似值”实际上是一年中确切的天数(这就是我们为什么要有闰年——来弥补四分之一天),通过适当的舍入,你总能得到一个正确的年数。 - montonero

11
int Age = new DateTime((DateTime.Now - BirthDateTime).Ticks).Year;

为计算经过的年数(年龄),结果将减去一。
var timeSpan = DateTime.Now - birthDateTime;
int age = new DateTime(timeSpan.Ticks).Year - 1;

1
这实际上并不正确,因为它是四舍五入。我今年40岁,但它报告我41岁。我要再过3周才真正满41岁。 - Stephen York
1
此内容与编程有关: 此外,它不正确地计算了闰年。 - Mick

6

这里有一个巧妙的技巧,可以让系统自动处理闰年。它可以准确地计算所有日期组合。

DateTime dt1 = new DateTime(1987, 9, 23, 13, 12, 12, 0);
DateTime dt2 = new DateTime(2007, 6, 15, 16, 25, 46, 0);

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

Console.WriteLine("{0}", years);

这是一个不错的想法,但是你应该增加年数而不是在循环中更改tmp日期。如果你期望2012年2月29日至2016年2月29日返回4,那么这样做会正常工作。 - altso

5
不清楚你希望如何处理小数年份,但或许可以像这样处理:
DateTime now = DateTime.Now;
DateTime origin = new DateTime(2007, 11, 3);
int calendar_years = now.Year - origin.Year;
int whole_years = calendar_years - ((now.AddYears(-calendar_years) >= origin)? 0: 1);
int another_method = calendar_years - ((now.Month - origin.Month) * 32 >= origin.Day - now.Day)? 0: 1);

根据这种方法,2009年2月28日距2008年2月29日为1年,但实际上应该略少于1年。我想闰年的处理总是会让人感到不满意。 - o. nate
@o. nate:已修复,或许(使用Doggett发现的另一个问题上的技巧)。我认为像Dana的解决方案那样,在两个方向上修复闰年情况可能是必要的。 - Ben Voigt

3
我实现了一个扩展方法,用于获取两个日期之间的年数,按整月四舍五入。
    /// <summary>
    /// Gets the total number of years between two dates, rounded to whole months.
    /// Examples: 
    /// 2011-12-14, 2012-12-15 returns 1.
    /// 2011-12-14, 2012-12-14 returns 1.
    /// 2011-12-14, 2012-12-13 returns 0,9167.
    /// </summary>
    /// <param name="start">
    /// Stardate of time period
    /// </param>
    /// <param name="end">
    /// Enddate of time period
    /// </param>
    /// <returns>
    /// Total Years between the two days
    /// </returns>
    public static double DifferenceTotalYears(this DateTime start, DateTime end)
    {
        // Get difference in total months.
        int months = ((end.Year - start.Year) * 12) + (end.Month - start.Month);

        // substract 1 month if end month is not completed
        if (end.Day < start.Day)
        {
            months--;
        }

        double totalyears = months / 12d;
        return totalyears;
    }

这个解决方案将每个月视为一年的1/12。它会有所偏差,因为有些月份的大小不是这样。 - Rhys Bevilaqua
不总是返回正确的结果。 - Mick

2
我在TimeSpan for years, months and days上找到了这个:
DateTime target_dob = THE_DOB;
DateTime true_age = DateTime.MinValue + ((TimeSpan)(DateTime.Now - target_dob )); // Minimum value as 1/1/1
int yr = true_age.Year - 1;

无法处理闰年...请尝试从“1973年10月6日”到“2024年10月5日”。它报告我的年龄为51岁,但我只有50岁。 - NobleGuy

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