Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как рассчитать чей-то возраст на Java?

Автор вопроса: nojeviveОтветов: 12

Я хочу вернуть возраст в годах как int в методе Java. Теперь у меня есть следующее, где getBirthDate () возвращает объект Date (с датой рождения ;-)):

public int getAge() {
    long ageInMillis = new Date().getTime() - getBirthDate().getTime();

    Date age = new Date(ageInMillis);

    return age.getYear();
}

Но поскольку getYear () устарел, мне интересно, есть ли лучший способ сделать это? Я даже не уверен, что это работает правильно, поскольку у меня нет модульных тестов (пока).

  • Изменил свое мнение об этом: в другом вопросе есть только приблизительное количество лет между датами, а не действительно правильный возраст. cletus 12.07.2009
  • Учитывая, что он возвращает int, можете ли вы пояснить, что вы подразумеваете под "правильным" возрастом? Brian Agnew 12.07.2009
  • Дата и календарь - это фундаментальная концепция, которую можно почерпнуть из документации по Java. Я не могу понять, почему за это так проголосовали. demongolem 04.07.2012
  • @demongolem ??? Дата и календарь легко понять ?! Нет, совсем нет. Здесь, в Stack Overflow, есть миллион вопросов по этой теме. В рамках проекта Joda-Time была создана одна из самых популярных библиотек, которая заменила эти неудобные классы времени и даты. Позже Sun, Oracle и сообщество JCP приняли JSR 310 ( java.time), признавая, что унаследованные классы были безнадежно неадекватными. Для получения дополнительной информации см. Руководство от Oracle . Basil Bourque 01.03.2018

javadatecalendar

Ответы

Ответ 1 · рейтинг 176 · duffymo

JDK 8 делает это легко и элегантно:

public class AgeCalculator {

    public static int calculateAge(LocalDate birthDate, LocalDate currentDate) {
        if ((birthDate != null) && (currentDate != null)) {
            return Period.between(birthDate, currentDate).getYears();
        } else {
            return 0;
        }
    }
}

Тест JUnit для демонстрации его использования:

public class AgeCalculatorTest {

    @Test
    public void testCalculateAge_Success() {
        // setup
        LocalDate birthDate = LocalDate.of(1961, 5, 17);
        // exercise
        int actual = AgeCalculator.calculateAge(birthDate, LocalDate.of(2016, 7, 12));
        // assert
        Assert.assertEquals(55, actual);
    }
}

К настоящему времени все должны использовать JDK 8. Срок службы поддержки всех более ранних версий истек.

Ответ 2 · рейтинг 173 · Brian Agnew

Ознакомьтесь с Joda, который упрощает вычисления даты и времени (Joda также является основой новой стандартной даты Java / time apis, так что вы изучите API, который скоро станет стандартом).

РЕДАКТИРОВАТЬ: Java 8 имеет что-то очень похожее, и его стоит проверить.

e.g.

LocalDate birthdate = new LocalDate (1970, 1, 20);
LocalDate now = new LocalDate();
Years age = Years.yearsBetween(birthdate, now);

это так просто, как вы могли бы пожелать. Материал до Java 8 (как вы определили) несколько не интуитивно понятен.

Ответ 3 · рейтинг 44 · Meno Hochschild

Современный ответ и обзор

а) Java-8 (пакет java.time)

LocalDate start = LocalDate.of(1996, 2, 29);
LocalDate end = LocalDate.of(2014, 2, 28); // use for age-calculation: LocalDate.now()
long years = ChronoUnit.YEARS.between(start, end);
System.out.println(years); // 17

Обратите внимание, что выражение LocalDate.now() неявно связано с системным часовым поясом (который часто упускается из виду пользователями). Для ясности обычно лучше использовать перегруженный метод now(ZoneId.of("Europe/Paris")), указав явный часовой пояс (здесь, например, "Европа / Париж"). Если запрашивается системный часовой пояс, я лично предпочитаю написать LocalDate.now(ZoneId.systemDefault()), чтобы сделать связь с системным часовым поясом более ясной. Это больше усилий при письме, но облегчает чтение.

б) Джода-Тайм

Обратите внимание, что предложенное и принятое решение Joda-Time дает другой результат вычислений для дат, указанных выше (редкий случай), а именно:

LocalDate birthdate = new LocalDate(1996, 2, 29);
LocalDate now = new LocalDate(2014, 2, 28); // test, in real world without args
Years age = Years.yearsBetween(birthdate, now);
System.out.println(age.getYears()); // 18

Я считаю это небольшой ошибкой, но команда Joda имеет другой взгляд на это странное поведение и не хочет его исправлять (странно, потому что день месяца конечной даты меньше даты начала, поэтому год должен быть одним меньще). См. Также эту закрытую проблему.

c) java.util.Calendar и т. д.

Для сравнения см. Различные другие ответы. Я бы вообще не рекомендовал использовать эти устаревшие классы, потому что результирующий код все еще подвержен ошибкам в некоторых экзотических случаях и / или слишком сложен, учитывая тот факт, что исходный вопрос звучит так просто. В 2015 году у нас действительно лучшие библиотеки.

г) О Date4J:

Предлагаемое решение простое, но в високосные годы иногда дает сбой. Просто оценить день года ненадежно.

д) Моя собственная библиотека Time4J:

Это работает аналогично решению Java-8. Просто замените LocalDate на PlainDate и ChronoUnit.YEARS на CalendarUnit.YEARS. Однако для получения "сегодня" требуется явная ссылка на часовой пояс.

PlainDate start = PlainDate.of(1996, 2, 29);
PlainDate end = PlainDate.of(2014, 2, 28);
// use for age-calculation (today):
// => end = SystemClock.inZonalView(EUROPE.PARIS).today();
// or in system timezone: end = SystemClock.inLocalView().today();
long years = CalendarUnit.YEARS.between(start, end);
System.out.println(years); // 17

Ответ 4 · рейтинг 14 · Lou Morda

Я просто использую постоянное значение миллисекунд в году в своих интересах:

Date now = new Date();
long timeBetween = now.getTime() - age.getTime();
double yearsBetween = timeBetween / 3.15576e+10;
int age = (int) Math.floor(yearsBetween);

Ответ 5 · рейтинг 13 · Craigo

Если вы используете GWT, вы будете ограничены использованием java.util.Date, вот метод, который принимает дату как целые числа, но по-прежнему использует java.util.Date:

public int getAge(int year, int month, int day) {
    Date now = new Date();
    int nowMonth = now.getMonth()+1;
    int nowYear = now.getYear()+1900;
    int result = nowYear - year;

    if (month > nowMonth) {
        result--;
    }
    else if (month == nowMonth) {
        int nowDay = now.getDate();

        if (day > nowDay) {
            result--;
        }
    }
    return result;
}

Ответ 6 · рейтинг 7 · weston

Возможно, удивительно отметить, что вам не нужно знать, сколько дней или месяцев в году или сколько дней в этих месяцах, точно так же вам не нужно знать о високосных годах, високосных секундах и т. Д. всего этого, используя этот простой, на 100% точный метод:

public static int age(Date birthday, Date date) {
    DateFormat formatter = new SimpleDateFormat("yyyyMMdd");
    int d1 = Integer.parseInt(formatter.format(birthday));
    int d2 = Integer.parseInt(formatter.format(date));
    int age = (d2-d1)/10000;
    return age;
}

Ответ 7 · рейтинг 5 · cass

Это улучшенная версия предыдущей ... учитывая, что вы хотите, чтобы age было int. потому что иногда вы не хотите заполнять свою программу кучей библиотек.

public int getAge(Date dateOfBirth) {
    int age = 0;
    Calendar born = Calendar.getInstance();
    Calendar now = Calendar.getInstance();
    if(dateOfBirth!= null) {
        now.setTime(new Date());
        born.setTime(dateOfBirth);
        if(born.after(now)) {
            throw new IllegalArgumentException("Can't be born in the future");
        }
        age = now.get(Calendar.YEAR) - born.get(Calendar.YEAR);
        if(now.get(Calendar.DAY_OF_YEAR) < born.get(Calendar.DAY_OF_YEAR))  {
            age-=1;
        }
    }
    return age;
}

Ответ 8 · рейтинг 5 · Fletch

Правильный ответ при использовании JodaTime:

public int getAge() {
    Years years = Years.yearsBetween(new LocalDate(getBirthDate()), new LocalDate());
    return years.getYears();
}

Вы можете даже сократить его до одной строки, если хотите. Я скопировал идею из ответа BrianAgnew, но я считаю, что это более правильно, как вы видите из комментариев там (и он отвечает вопрос именно).

Ответ 9 · рейтинг 4 · John

С помощью библиотеки date4j:

int age = today.getYear() - birthdate.getYear();
if(today.getDayOfYear() < birthdate.getDayOfYear()){
  age = age - 1;
}

Ответ 10 · рейтинг 3 · Kevin

Попробуйте скопировать это в свой код, а затем используйте метод, чтобы получить возраст.

public static int getAge(Date birthday)
{
    GregorianCalendar today = new GregorianCalendar();
    GregorianCalendar bday = new GregorianCalendar();
    GregorianCalendar bdayThisYear = new GregorianCalendar();

    bday.setTime(birthday);
    bdayThisYear.setTime(birthday);
    bdayThisYear.set(Calendar.YEAR, today.get(Calendar.YEAR));

    int age = today.get(Calendar.YEAR) - bday.get(Calendar.YEAR);

    if(today.getTimeInMillis() < bdayThisYear.getTimeInMillis())
        age--;

    return age;
}

Ответ 11 · рейтинг 3 · Ameen Maheen

Я использую этот фрагмент кода для расчета возраста. Надеюсь, это поможет ... библиотеки не использовались.

private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());

public static int calculateAge(String date) {

    int age = 0;
    try {
        Date date1 = dateFormat.parse(date);
        Calendar now = Calendar.getInstance();
        Calendar dob = Calendar.getInstance();
        dob.setTime(date1);
        if (dob.after(now)) {
            throw new IllegalArgumentException("Can't be born in the future");
        }
        int year1 = now.get(Calendar.YEAR);
        int year2 = dob.get(Calendar.YEAR);
        age = year1 - year2;
        int month1 = now.get(Calendar.MONTH);
        int month2 = dob.get(Calendar.MONTH);
        if (month2 > month1) {
            age--;
        } else if (month1 == month2) {
            int day1 = now.get(Calendar.DAY_OF_MONTH);
            int day2 = dob.get(Calendar.DAY_OF_MONTH);
            if (day2 > day1) {
                age--;
            }
        }
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return age ;
}

Ответ 12 · рейтинг 2 · John B

Поля рождение и эффект являются полями даты:

Calendar bir = Calendar.getInstance();
bir.setTime(birth);
int birthNm = bir.get(Calendar.DAY_OF_YEAR);
int birthYear = bir.get(Calendar.YEAR);
Calendar eff = Calendar.getInstance();
eff.setTime(effect);

По сути, это модификация решения Джона О без использования устаревших методов. Я потратил довольно много времени, пытаясь заставить его код работать в моем коде. Может быть, тогда это спасет других.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы