2012-03-07 161 views
2

你好所以我实现了这个解决方案,从一个生日日期输入获得用户的生日: Calculate age in C#生日年龄计算,而且数月的天数

这个伟大的工程,但是我确实需要解释的生日的年龄不到一年(婴儿,婴儿)。如果当天和当前日期之间的时间少于365天,它现在只会给我一个“0”的年龄。

我在想什么是这样的:

public string calculateAge(DateTime birthDate, DateTime now) 
     { 
      //BDay is in different year (age > 1) 
      int age = now.Year - birthDate.Year; 
      if (now.Month < birthDate.Month || (now.Month == birthDate.Month && now.Day < birthDate.Day)) age--; 

      if (age == 0) 
      { 
       //Bday is in same year 
       age = now.Month - birthDate.Month; 
       if (now.Month < birthDate.Month || (now.Month == birthDate.Month && now.Day < birthDate.Day)) age--; 

       return age.ToString() + " months"; 
      } 
      if (age == 0) 
      { 
       //Bday is in the same month 
       age = now.Day - birthDate.Day; 
       if (now.Month < birthDate.Month || (now.Month == birthDate.Month && now.Day < birthDate.Day)) age--; 

       return age.ToString() + " days"; 
      } 
      return age.ToString(); 
     } 

但是我的一些测试Bdays的给我这个:

(Today's date: 3/6/2012) 
Bday1 = 3/5/2012 
Age result = -1 
Expected result = 1 day 

Bday2 = 3/1/2012 
Age result = 0 months 
Expected result = 5 days 

Bday3 = 1/1/2012 
Age result = 2 months 
Expected result = 2 months (this is fine) 

Bday4 = 3/7/2011 
Age result = -1 months 
Expected result = 11 months 

Bday5 = 3/1/2011 
Age result = 1 
Expected result = 1 (this is fine) 

你可以看到,因为它是目前设置了如何问题源于bday月份小于当前月份的某些负数可能导致的结果。

我也看到关于不能进入“天”循环的错误,但我认为这是一个毫无意义的问题。如果您对我可以做些什么以获得理想的结果有所了解,请告诉我。另外如果你需要更多的信息,比如测试bdays。谢谢!

回答

1
static public string calculateAge(DateTime birthDate, DateTime now) 
{ 
    birthDate = birthDate.Date; 
    now = now.Date; 

    var days = now.Day - birthDate.Day; 
    if (days < 0) 
    { 
    var newNow = now.AddMonths(-1); 
    days += (int)(now - newNow).TotalDays; 
    now = newNow; 
    } 
    var months = now.Month - birthDate.Month; 
    if (months < 0) 
    { 
    months += 12; 
    now = now.AddYears(-1); 
    } 
    var years = now.Year - birthDate.Year; 
    if (years == 0) 
    { 
    if (months == 0) 
     return days.ToString() + " days"; 
    else 
     return months.ToString() + " months"; 
    } 
    return years.ToString(); 
} 

结果(现在 - 2012/3/7):

3/5/2012: 2 days 
    3/1/2012: 6 days 
    1/1/2012: 2 months 
    3/8/2011: 11 months 
    3/1/2011: 1 
0

你可以有点接近这个功能,我发现:

/// <summary> 
/// Converts a timespan value to a string representation. 
/// </summary> 
/// <param name="time_span">the amount of time to convert to words</param> 
/// <param name="whole_seconds">round up the seconds</param> 
/// <returns>4 minutes, 58 seconds, etc</returns> 
/// <remarks>If it can't convert to a string, it returns "Calculating time remaining..."</remarks> 
public string TimespanToWords(TimeSpan time_span, bool whole_seconds = true) 
{ 
    TimeSpan span; 
    string str2 = ""; 
    if (time_span.Days > 0) 
    { 
     str2 = str2 + ", " + time_span.Days.ToString() + " days"; 
     span = new TimeSpan(time_span.Days, 0, 0, 0); 
     time_span = time_span.Subtract(span); 
    } 
    if (time_span.Hours > 0) 
    { 
     str2 = str2 + ", " + time_span.Hours.ToString() + " hours"; 
     span = new TimeSpan(0, time_span.Hours, 0, 0); 
     time_span = time_span.Subtract(span); 
    } 
    if (time_span.Minutes > 0) 
    { 
     str2 = str2 + ", " + time_span.Minutes.ToString() + " minutes"; 
     span = new TimeSpan(0, 0, time_span.Minutes, 0); 
     time_span = time_span.Subtract(span); 
    } 
    if (whole_seconds) 
    { 
     if (time_span.Seconds > 0) 
     { 
      str2 = str2 + ", " + time_span.Seconds.ToString() + " seconds"; 
     } 
    } 
    else 
    { 
     str2 = str2 + ", " + time_span.TotalSeconds.ToString() + " seconds"; 
    } 
    if (str2.Length > 0) 
    { 
     str2 = str2.Substring(2); 
    } 
    if (string.IsNullOrEmpty(str2)) 
    { 
     return "Calculating time remaining..."; 
    } 
    return str2; 
} 

下面是如何使用它:

var date1 = System.DateTime.Parse("01/01/1999"); 
    var date2 = System.DateTime.Parse("03/07/2012"); 


    var ts = date2 - date1; 

    var timeString = TimespanToWords(ts, true); 
1

实际上,我们有我们的框架中一个“DateSpan”结构做类似的计算...它的关键是你所追求的是低于哪里通过一个定义的“开始”和“结束”DateTime变量它具有如下属性:

public int WholeMonths 
    { 
     get 
     { 
      var startInEndsYear = Start.AddYears(End.Year - Start.Year); 

      // Are within a month of each other if EITHER: 
      // 1. Month is the same 
      // 2. Month period is within 1 
      // AND 
      // The difference between days of the year is less than the number of days in the start's month 
      var sameMonth = End.Month == startInEndsYear.Month || (End.Month - 1 == Start.Month && (End.DayOfYear - startInEndsYear.DayOfYear)/(double)DateTime.DaysInMonth(startInEndsYear.Year, startInEndsYear.Month) < 1.0d); 
      var sameMonthAndDay = sameMonth && End.Day == Start.Day; 

      var res = (End.Year - Start.Year) * 12; 
      if (sameMonth && !sameMonthAndDay) 
      { 
       res -= (startInEndsYear > End) ? 1 : 0; 
      } 
      else if (sameMonthAndDay) 
      { 
       res -= (End.TimeOfDay < Start.TimeOfDay ? 1 : 0); 
      } 
      else 
      { 
       res -= Start.Month; 
       res += End.Month; 
      } 
      return res; 
     } 
    } 
012对个

和从属属性:

public int WholeYears 
    { 
     get 
     { 
      return (int) Math.Floor(WholeMonths/12d); 
     } 
    } 

    public int PartMonths 
    { 
     get 
     { 
      return WholeMonths % 12; 
     } 
    } 

我会离开它作为进一步的锻炼,为您转换成基于这些特性的话。

编辑:下面是各天的计算:

public TimeSpan PartDays 
    { 
     get 
     { 
      var startInEndsMonth = Start.AddMonths(WholeMonths); 
      return End.Subtract(startInEndsMonth); 
     } 
    } 
+0

上面并没有考虑到 “天”。但是,将它留在这里为后代无论如何... – Reddog 2012-03-07 01:59:35

1

这里有一种方法,其计算在西方文化中,一个正常人的年龄将会为CE dates这样做。不同的文化和日历以不同的方式计算年龄。例如,China and other countries in Asia认为一个新生婴儿出生的那一天就是一岁,而他的年龄在中国农历的每一个农历新年都会记录下来。所以如果一个孩子出生,比如在农历新年前一个月,他会在那个月1岁,然后在他出生后的一个月内蜱达到2岁。

此算法不适用于BCE日期或从Julian转换到公历的日期。无论如何,无论如何分割它,这都是无稽之谈,因为不同的地点,即使在同一个国家内,也会在不同的时间切换:例如,直到布尔什维克革命之后,俄罗斯才改用格里历。

enter image description here

所以除非你有开始日期的语言环境和结束日期的语言环境,你不能准确计算整个朱利安/格利高里鸿沟的时间跨度。

的算法是:

  • 找到基准日,或在当前日期之前最近的月度生日。

    • 如果当天的最月是之前出生的实际日期,使用前一个月。如果实际出生日期晚于该月份的最后一天,请在当月的最后一天将其封顶。

      例如,如果当前日期为2012年3月7日和实际生日是'31 1990' 年3月,您基准日是2月29日,2012年

  • 计算的区别在您的参考日期和年份和月份的出生日期之间。这很容易,因为在西方日历中,年份的数量持续数月。您可以使用整数除法:

    int totalMonths =(12 * endYear + endMonth) - (12 * startYear + startMonth); int年= totalMonths/12; int months = totalMonths%12;

或者你可以减去并在必要时携带。

int years = endYear - startYear ; 
int months = endMonth - startMonth ; 

if (months < 0) 
{ 
    months += 12 ; 
    years -= 1 ; 
} 

结果在任何一种情况下应该是相同的。

天组件是从参考日期到当前日期的天数。

使用这种算法,在出生当天就是0天。

这里是我的代码:

static class HumanAgeFactory 
{ 

    public static HumanAge ComputeAge(this DateTime dob) 
    { 
    return dob.ComputeAgeAsOf(DateTime.Now) ; 
    } 

    public static HumanAge ComputeAgeAsOf(this DateTime dob , DateTime now) 
    { 
    dob = dob.Date ; // toss the time component 
    now = now.Date ; // toss the time component 

    if (dob > now) throw new ArgumentOutOfRangeException("dob" , "'now' must be on or after 'dob'") ; 

    DateTime mostRecentBirthDay = MostRecentNthDayOfTheMonthOnOrBefore(dob.Day , now) ; 
    int  years    = mostRecentBirthDay.Year - dob.Year   ; 
    int  months    = mostRecentBirthDay.Month - dob.Month   ; 
    int  days    = (int) (now - mostRecentBirthDay).TotalDays ; 

    if (months < 0) 
    { 
     months += 12 ; 
     years -= 1 ; 
    } 

    if (days < 0) throw new InvalidOperationException() ; 
    if (months < 0) throw new InvalidOperationException() ; 
    if (years < 0) throw new InvalidOperationException() ; 

    HumanAge instance = new HumanAge(years , months , days) ; 
    return instance ; 
    } 

    private static DateTime MostRecentNthDayOfTheMonthOnOrBefore(int nthDay , DateTime now) 
    { 
    if (nthDay < 1) throw new ArgumentOutOfRangeException("dayOfBirth") ; 

    int year = now.Year ; 
    int month = now.Month ; 

    if (nthDay > now.Day) 
    { 
     --month ; 
     if (month < 1) 
     { 
     month += 12 ; 
     year -= 1 ; 
     } 
    } 

    int daysInMonth = CultureInfo.CurrentCulture.Calendar.GetDaysInMonth(year , month) ; 
    int day   = (nthDay > daysInMonth ? daysInMonth : nthDay) ; 

    DateTime instance = new DateTime(year , month , day) ; 
    return instance ; 
    } 

} 

public class HumanAge 
{ 
    public int Years { get ; private set ; } 
    public int Months { get ; private set ; } 
    public int Days { get ; private set ; } 

    public override string ToString() 
    { 
    string instance = string.Format("{0} {1} , {2} {3} , {4} {5}" , 
     Years , Years == 1 ? "year" : "years" , 
     Months , Months == 1 ? "month" : "months" , 
     Days , Days == 1 ? "day" : "days" 
    ) ; 
    return instance ; 
    } 

    public HumanAge(int years , int months , int days) 
    { 
    if (years < 0    ) throw new ArgumentOutOfRangeException("years" ) ; 
    if (months < 0 || months > 12) throw new ArgumentOutOfRangeException("months") ; 
    if (days < 0 || days > 31) throw new ArgumentOutOfRangeException("days" ) ; 

    this.Years = years ; 
    this.Months = months ; 
    this.Days = days ; 

    return ; 
    } 

} 
0
int[] getAge(DateTime dt) 
    { 
     DateTime today = DateTime.Now; 
     int years = 0; 
     int days = 0; 
     int months = 0; 
     int[] age = new int[3]; 
     while (dt.Year != today.Year || dt.Month != today.Month || dt.Day != today.Day) 
     { 
      if (dt.AddYears(1).CompareTo(today) <= 0) 
      { 
       years++; 
       dt = dt.AddYears(1); 
      } 
      else 
      { 
       if (dt.AddMonths(1).CompareTo(today) <= 0) 
       { 
        months++; 
        dt = dt.AddMonths(1); 
       } 
       else 
       { 
        if (dt.AddDays(1).CompareTo(today) <= 0) 
        { 
         days++; 
         dt = dt.AddDays(1); 
        } 
        else 
        { 
         dt = today; 
        } 
       } 

      } 
     } 
     age[0] = years; 
     age[1] = months; 
     age[2] = days; 
     return age; 
    } 
+0

这是正确的一个 – 2013-04-24 10:48:00

+0

嗨,欢迎来到堆栈溢出。你可以通过说明它的作用,它是如何解决问题的,并且可能列出与其他解决方案相比的好处来改进你的答案。为了改进它,您可以点击答案下的编辑按钮。 – Ren 2013-04-24 11:01:59

2

您可以使用Time Period Library for .NET则DateDiff类:

// ---------------------------------------------------------------------- 
public void DateDiffSample() 
{ 
    DateTime date1 = new DateTime(2009, 11, 8, 7, 13, 59); 
    Console.WriteLine("Date1: {0}", date1); 
    // > Date1: 08.11.2009 07:13:59 
    DateTime date2 = new DateTime(2011, 3, 20, 19, 55, 28); 
    Console.WriteLine("Date2: {0}", date2); 
    // > Date2: 20.03.2011 19:55:28 

    DateDiff dateDiff = new DateDiff(date1, date2); 

    // elapsed 
    Console.WriteLine("DateDiff.ElapsedYears: {0}", dateDiff.ElapsedYears); 
    // > DateDiff.ElapsedYears: 1 
    Console.WriteLine("DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths); 
    // > DateDiff.ElapsedMonths: 4 
    Console.WriteLine("DateDiff.ElapsedDays: {0}", dateDiff.ElapsedDays); 
    // > DateDiff.ElapsedDays: 12 
} // DateDiffSample