Подтвердить что ты не робот

Как я могу рассчитать возраст человека в год, месяц, дни?

Я хочу рассчитать возраст человека с датой рождения и текущей датой в годах, месяцах и днях относительно текущей даты.

Например:

>>> calculate_age(2008, 01, 01)
1 years, 0 months, 16 days

Любой указатель на алгоритм, который делает это, будет оценен.

4b9b3361

Ответ 1

Во-первых, обратите внимание на предположение, что если, например, вы родились 1 февраля, а затем 1 марта, вам ровно 1 месяц, даже если ваш возраст в днях составляет всего 28 - меньше, чем длина средний месяц. Годы также имеют переменную длину (из-за високосных лет), что означает, что ваш возраст в день вашего рождения обычно не является точным целым числом лет. Если вы хотите выразить точное количество времени, которое вы были живы в годах/месяцах/днях, см. Мой другой ответ. Но, скорее всего, вы хотите погладить это правильно, чтобы рождение 1 февраля означало, что каждый 1 февраля вы являетесь X лет, 0 месяцев и 0 дней, а 1-го числа любого месяца вы - X лет, Y месяцев, и 0 дней.

В этом случае читайте дальше. (NB: следующие работы работают только в датах в прошлом.)

Учитывая дату рождения, (y,m,d), текущую дату, (ynow,mnow,dnow) и функцию tm(), которая дает unix/epoch time для заданной даты, следующий будет выводить список из 3 элементов, дающий возраст как {годы, месяцы, дни}:

t0 = y*12 + m - 1;        # total months for birthdate.
t = ynow*12 + mnow - 1;   # total months for Now.
dm = t - t0;              # delta months.    
if(dnow >= d) return [floor(dm/12), mod(dm,12), dnow-d];
dm--; t--;
return [floor(dm/12), mod(dm,12), 
        (tm({ynow,mnow,dnow}) - tm({floor(t/12), mod(t,12)+1, d}))/60/60/24];

Ниже приведен эквивалентный алгоритм, если вам не нравятся все этажи и моды. Но я думаю, что это выше. Во-первых, он избегает вызова tm(), когда это не нужно.

{yl, ml} = {ynow, mnow};
if(mnow < m || mnow == m && dnow < d) yl--;
if(dnow < d) ml--;
years = yl - y;
months = ml + 12*(ynow - yl) - m;
yl = ynow;
if(ml == 0) { ml = 12; yl--; }
days = (tm({ynow, mnow, dnow}) - tm({yl, ml, d}))/60/60/24;
return [years, months, days];

Ответ 2

Это непростой вопрос, так как выше дней (если мы не учитываем прыжок-секунды), нелегко формулы.

Месяцы могут состоять из 28, 29, 30 или 31 дней; лет может составлять 365 или 366 дней. Поэтому возникают проблемы, когда вы пытаетесь рассчитать полные единицы времени в течение нескольких месяцев и лет.

Вот интересная статья, в которой учитываются все сложные аспекты решения вашего вопроса на Java.

Ответ 3

Другие здесь имеют правильную идею - вам просто нужно иметь возможность распространять ее на другие языки. Многие компьютерные системы отсчитывают время в секундах от определенной точки ( "эпоха" или "контрольная дата" ) и определяют дату оттуда, а также предлагают методы для преобразования от секунд до дат. Вы должны иметь возможность получить текущее время в секундах, преобразовать дату рождения в секундах от эпохи, вычесть два значения, а затем разделить это на количество секунд в день:

int timenow = time(0);
struct tm birthday = { tm_mday = 16 , .tm_mon = 1 , .tm_year = 1963 };
int timebirth = mktime( &birthday_tm );
int diff_sec = timenow - timebirth;
int days = diff_sec / ( 24 * 60 * 60);
printf("%d - %d = %d seconds, or %d days\n", timenow, timebirth, diff_sec, days);

Ошибка в этом конкретном коде состоит в том, что mktime() не может иметь дело с датами до эпохи, которая составляет 1 января 1970 года в системах на базе Unix. Подобные проблемы будут существовать и в других системах в зависимости от того, как они рассчитывают время. Общий алгоритм должен работать, вам просто нужно знать свои ограничения на конкретные системы.

Ответ 4

В python-списке обсуждается, почему вычисление возраста не является настолько простой задачей.

Из этого обсуждения я нашел эту реализацию (которую я не буду копировать и вставлять сюда, потому что это не мое).

Однако я не обнаружил ни одной записи в библиотеках.

Ответ 5

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

Как записывается этот алгоритм, зависит от языка, который вы используете, потому что каждый язык имеет другой набор функций. Моя собственная реализация на Java, используя неудобный, но технически правильный GregorianCalendar:

Term difference (Date from, Date to) {
    GregorianCalendar cal1 = new GregorianCalendar();
    cal1.setTimeInMillis(from.getTime());

    GregorianCalendar cal2 = new GregorianCalendar();
    cal2.setTimeInMillis(to.getTime());

    int years = cal2.get(Calendar.YEAR) - cal1.get(Calendar.YEAR);
    int months = cal2.get(Calendar.MONTH) - cal1.get(Calendar.MONTH);
    int days = cal2.get(Calendar.DAY_OF_MONTH) - cal1.get(Calendar.DAY_OF_MONTH);
    if (days < 0) {
        months--;
        days += cal1.getActualMaximum(Calendar.DAY_OF_MONTH);
    }
    if (months < 0) {
        years--;
        months += 12;
    }
    return new Term(years, months, days);
}

Это может быть не совсем идеально, но он дает читаемые человеком результаты. Термин является моим собственным классом для хранения периодов человеческого стиля, поскольку в библиотеках дат Java нет его.

Для будущих проектов я планирую перейти к гораздо лучшей библиотеке даты и времени Joda, которая имеет в ней класс Period, и, вероятно, придется переписать эту функцию.

Ответ 6

Я предполагаю, что вопросы шире, чем только один язык программирования. Если вы используете С#, вы можете использовать DateTimeOffset для вычисления этого.

var offset = DateTimeOffset.MinValue;
var lastDate = DateTime.Today;
var firstDate = new DateTime(2006,11,19);


var diff = (lastDate- firstDate);
var resultWithOffset = DateTimeOffset.MinValue.AddDays(diff.TotalDays);
var result = resultWithOffset.AddDays(-offset.Day).AddMonths(-offset.Month).AddYears(-offset.Year);

result.Day, result.Month, result.Year будет содержать необходимую информацию.

Ответ 7

Вот способ сделать это, если вы хотите нарушить принцип "Я должен быть целым числом лет в мой день рождения". Обратите внимание, что этот принцип не является строгим, из-за високосных лет, поэтому следующее на самом деле более точное, хотя, возможно, менее интуитивное. Если вы хотите узнать точное точное число лет, кто-то есть, так я бы это сделал.

Сначала преобразуйте дату рождения и текущее время в эпоху (количество секунд с начала рассвета, т.е. 1970 год на земле unix) и вычтите их. См. Например, этот вопрос, как это сделать: Как конвертировать дату/время в эпоху (ака unix time - секунды с 1970 года) в Perl?, Теперь у вас есть человек точный возраст в секундах и нужно преобразовать его в строку типа "36 лет, 3 месяца, 8 дней".

Здесь псевдокод, чтобы сделать это. Это должно быть просто, чтобы удалить недели или часы или любые части, которые вы не хотите...

daysInYear = 365.2425;  # Average lengh of a year in the gregorian calendar.
                        # Another candidate for len of a year is a sidereal year,
                        # 365.2564 days.  cf. http://en.wikipedia.org/wiki/Year
weeksInYear = daysInYear / 7;
daysInMonth = daysInYear / 12;
weeksInMonth = daysInMonth / 7;
sS = 1;
mS = 60*sS;
hS = 60*mS;
dS = 24*hS;
wS = 7*dS;
oS = daysInMonth*dS;
yS = daysInYear*dS;

# Convert a number of seconds to years,months,weeks,days,hrs,mins,secs.
seconds2str[secs] 
{
  local variables:
    y, yQ= False, o, oQ= False, w, wQ= False,
    d, dQ= False, h, hQ= False, m, mQ= False, s= secs;

  if(secs<0) return "-" + seconds2str(-secs);  # "+" is string concatenation.

  y = floor(s/yS);
  if(y>0) yQ = oQ = wQ = dQ = hQ = mQ = True;
  s -= y * yS;

  o = floor(s/oS);
  if(o>0) oQ = wQ = dQ = hQ = mQ = True;
  s -= o * oS;

  w = floor(s/wS);
  if(w>0) wQ = dQ = hQ = mQ = True;
  s -= w * wS;

  d = floor(s/dS);
  if(d>0) dQ = hQ = mQ = True;
  s -= d * dS;

  h = floor(s/hS);
  if(h>0) hQ = mQ = True;
  s -= h * hS;

  m = floor(s/mS);
  if(m>0) mQ = True;
  s -= m * mS;

  return
    (yQ ? y + " year"  + maybeS(y) + " " : "") + 
    (oQ ? o + " month" + maybeS(o) + " " : "") + 
    (wQ ? w + " week"  + maybeS(w) + " " : "") + 
    (dQ ? d + " day"   + maybeS(d) + " " : "") + 
    (hQ ? dd(h) + ":" : "") + 
    (mQ ? dd(m) + ":" + dd(round(s)) + "s" : s + "s");
}


# Returns an "s" if n!=1 and "" otherwise.
maybeS(n) { return (n==1 ? "" : "s"); }

# Double-digit: takes a number from 0-99 and returns it as a 2-character string.
dd(n) { return (n<10 ? "0" + tostring(n) : tostring(n)); }

Ответ 8

Думаю, вам нужно немного уточнить требования.

Скажем, дата рождения 2008-02-01 и день 2009-01-31

Каков результат?

  • 0 лет, 11 месяцев и 31 день?
  • 0 лет, 10 месяцев и 28 + 31 = 59 дней?
  • 0 лет, 10 месяцев и 29 + 31 = 60 дней?

Ответ 9

Вот это с использованием правила заимствования математики.

        DateTime dateOfBirth = new DateTime(2000, 4, 18);
        DateTime currentDate = DateTime.Now;

        int ageInYears = 0;
        int ageInMonths = 0;
        int ageInDays = 0;

        ageInDays = currentDate.Day - dateOfBirth.Day;
        ageInMonths = currentDate.Month - dateOfBirth.Month;
        ageInYears = currentDate.Year - dateOfBirth.Year;

        if (ageInDays < 0)
        {
            ageInDays += DateTime.DaysInMonth(currentDate.Year, currentDate.Month);
            ageInMonths = ageInMonths--;

            if (ageInMonths < 0)
            {
                ageInMonths += 12;
                ageInYears--;
            }
        }
        if (ageInMonths < 0)
        {
            ageInMonths += 12;
            ageInYears--;
        }

        Console.WriteLine("{0}, {1}, {2}", ageInYears, ageInMonths, ageInDays);

Ответ 10

Быстрая реализация ответа на трини.

пс. вместо (y, m, d) (ynow, mnow, dnow) в качестве входных данных я использую два NSDate, которые могут быть более удобными в реальных действиях.

extension NSDate {

    convenience init(ageDateString:String) {
        let dateStringFormatter = NSDateFormatter()
        dateStringFormatter.dateFormat = "yyyy-MM-dd"
        dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
        let d = dateStringFormatter.dateFromString(ageDateString)!
        self.init(timeInterval:0, sinceDate:d)
    }

    func ageFrom(date: NSDate) -> (Int, Int, Int) {
        let cal = NSCalendar.currentCalendar()

        let y = cal.component(NSCalendarUnit.Year, fromDate: date)
        let m = cal.component(NSCalendarUnit.Month, fromDate: date)
        let d = cal.component(NSCalendarUnit.Day, fromDate: date)
        let ynow = cal.component(NSCalendarUnit.Year, fromDate: self)
        let mnow = cal.component(NSCalendarUnit.Month, fromDate: self)
        let dnow = cal.component(NSCalendarUnit.Day, fromDate: self)

        let t0 = y * 12 + m - 1       // total months for birthdate.
        var t = ynow * 12 + mnow - 1;   // total months for Now.
        var dm = t - t0;              // delta months.
        if(dnow >= d) {
            return (Int(floor(Double(dm)/12)), dm % 12, dnow - d)
        }
        dm--
        t--
        return (Int(floor(Double(dm)/12)), dm % 12, Int((self.timeIntervalSince1970 - NSDate(ageDateString: "\(Int(floor(Double(t)/12)))-\(t%12 + 1)-\(d)").timeIntervalSince1970)/60/60/24))
    }

}

// sample usage
let birthday = NSDate(ageDateString: "2012-7-8")
print(NSDate().ageFrom(birthday))

Ответ 11

Я знаю, это немного устарело, но вот простой код, который я использовал, с мощью библиотеки Python (Python 3.5 для аннотаций, но работает без).

from datetime import date, timedelta

def age(birth: date) -> (int, int, int):
        """
            Get a 3-int tuple telling the exact age based on birth date.
        """
        today_age = date(1, 1, 1) + (date.today() - birth)
        # -1 because we start from year 1 and not 0.
        return (today_age.year - 1, today_age.month - 1, today_age.day - 1)

Ответ 12

Поскольку вы явно используете python: создайте объекты datetime, один с "днем рождения" и один с "сейчас", вычтите их и прочитайте возраст из результирующего объекта timedelta.

Зачем беспокоиться о таких вещах, как високосные годы?