生日年龄计算,也适用于月数和天数

时间:2012-03-07 01:34:30

标签: c# date

你好我已经实现了这个解决方案,以便从生日日期输入获得用户的生日: Calculate age in C#

这很好但是我需要解释生日不到一年的年龄(婴儿,婴儿)。如果bdate和当前日期之间的时间少于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();
        }

然而,我的一些测试Bday给了我这个:

(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。谢谢!

6 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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

答案 2 :(得分:1)

我们实际上有一个&#34; DateSpan&#34;在我们的框架中进行类似计算的结构......它与你所追求的内容相关的关键点在于定义的&#34;开始&#34;和&#34;结束&#34; 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;
        }
    }

依赖属性:

    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);
        }
    }

答案 3 :(得分:1)

这是一种方式,它计算西方文化中正常人为CE dates做这件事的年龄。不同的文化和日历以不同的方式估计年龄。例如,China and other countries in Asia估计一个新生婴儿在他出生的那天是1岁,并且在中国历法的每个农历新年中他的年龄都会上升。因此,如果一个孩子在农历新年前一个月出生,那么他将在那个月成为1岁,然后在他出生后一个月就会达到2岁。

此算法不适用于BCE日期或跨越从Julian到Gregorian日历的过渡日期。无论如何,无论你如何分割,这都是冒险的命题,因为不同的地点,即使在同一个国家,也在不同的时间切换:俄罗斯在布尔什维克革命之后没有改为公历。

enter image description here

因此,除非你有开始日期的语言环境和结束日期的语言环境,否则你不能准确计算Julian / Gregorian鸿沟的时间跨度。

算法是:

  • 找到参考日期,即当前日期或之前的最近一个月生日。

    • 如果当前的日期早于实际出生日期,请使用前一个月。如果实际出生日期晚于该月的最后一天,请将其限制在该月的最后一天。

      例如,如果当前日期是2012年3月7日,实际生日是'1990年3月31日',那么参考日期是2012年2月29日。

  • 计算您的参考日期与出生日期之间的差异,以年和月为单位。这很容易,因为在西历中,年份具有一致的月数。您可以使用整数除法:

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

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

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

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

在任何一种情况下,结果都应该相同。

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

使用此算法,出生当天就有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 ;
  }

}

答案 4 :(得分: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);

答案 5 :(得分: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;
    }