расчет возраста дня рождения, а также количества месяцев и дней - PullRequest
1 голос
/ 07 марта 2012

Здравствуйте, поэтому я реализовал это решение, чтобы получить день рождения пользователя по дате ввода: Рассчитать возраст в C #

Это прекрасно работает, однако мне нужно интерпретировать день рождения для возрастаменьше года (дети, младенцы).Текущий просто даст мне возраст "0", если между bdate и текущей датой меньше 365 дней.

Я думаю, что-то вроде этого:

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 меньше текущего месяца, некоторые отрицательные числа могутрезультат.

Я также вижу ошибку из-за невозможности попасть в цикл "дней", но я думаю, что сейчас это спорный вопрос.Дайте мне знать, если у вас есть понимание того, что я могу сделать, чтобы получить желаемые результаты.Также, если вам нужна дополнительная информация, например, тестовые дни.Спасибо!

Ответы [ 6 ]

2 голосов
/ 25 апреля 2013

Вы можете использовать DateDiff класс Библиотека периодов времени для .NET :

// ----------------------------------------------------------------------
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 голосов
/ 07 марта 2012
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();
} 

результаты (на данный момент - 3/7/2012):

  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 голос
/ 07 марта 2012

Вот один способ, который вычисляет возраст так, как нормальный человек в западной культуре сделал бы это для дат CE .Разные культуры и календари считаются возрастом по-разному.Например, Китай и другие страны Азии считают, что новорожденному ребенку будет 1 год в день его рождения, и его возраст отмечается в каждый последующий лунный Новый год по китайскому календарю.Так, если бы ребенок родился, скажем, за месяц до Лунного Нового года, ему бы исполнился 1 год в этом месяце, а затем он отмечал бы до 2 лет через месяц после его рождения.

Этот алгоритм не работаетне работает для дат BCE или для дат, охватывающих переход от юлианского к григорианскому календарю.В любом случае, это рискованное предложение, независимо от того, как вы его нарезаете, поскольку разные места, даже в пределах одной страны, переключались в разное время: Россия не переключалась на григорианский календарь, например, до окончания большевистской революции).

enter image description here

Итак, если у вас нет локали для даты начала и локали для даты окончания, вы не можете точно вычислить промежуток времени через юлианский / григорианский дележ.

Алгоритм:

  • Найти справочную дату , самый последний месячный день рождения в или до текущей даты.

    • Если текущий день месяца предшествует фактическому дню рождения, используйте предыдущий месяц.Если фактический день рождения позже, чем последний день месяца, ограничьте его последним днем ​​месяца.

      Например, если текущей датой является 7 марта 2012 года, а фактическим днем ​​рождения является '31 марта 1990 г., ваша контрольная дата - 29 февраля 2012 г.

  • Рассчитайте разницу между вашей контрольной датой и датойрождение в годах и месяцах.Это легко, потому что в западном календаре годы имеют постоянное количество месяцев.Вы можете использовать целочисленное деление:

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

}
1 голос
/ 07 марта 2012

У нас фактически есть структура "DateSpan" в нашей структуре для выполнения аналогичных вычислений ... Суть ее связана с тем, что вы ищете, ниже, где для определенной переменной "Start" и "End" 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);
        }
    }
0 голосов
/ 24 апреля 2013
    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 голосов
/ 07 марта 2012

Вы можете немного приблизиться к этой функции, которую я нашел:

/// <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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...