Как вычислить чей-то возраст в Java?
Я хочу вернуть возраст в годах как int в методе Java.
Теперь у меня есть следующее, где getBirthDate () возвращает объект даты (с датой рождения; -)):
public int getAge() {
long ageInMillis = new Date().getTime() - getBirthDate().getTime();
Date age = new Date(ageInMillis);
return age.getYear();
}
но поскольку getYear () является устаревшим, мне интересно, есть ли лучший способ сделать это? Я даже не уверен, что это работает правильно, так как у меня нет модульных тестов (пока).
28 ответов:
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. Все более ранние версии прошли конец их жизни поддержки.
проверить Джода, что упрощает вычисления даты/времени (Joda также является основой новых стандартных API Java date/time, поэтому вы скоро узнаете стандартный API).
EDIT: Java 8 имеет что-то очень похожее и стоит проверить.
например
LocalDate birthdate = new LocalDate (1970, 1, 20); LocalDate now = new LocalDate(); Years age = Years.yearsBetween(birthdate, now);это так просто, как вы могли бы хотеть. Материал pre-Java 8 (как вы определили) несколько неинтуитивен.
Calendar now = Calendar.getInstance(); Calendar dob = Calendar.getInstance(); dob.setTime(...); 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); int 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--; } } // age is now correct
современный ответ и обзор
a) Java-8 (java.time-package)
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 времени
обратите внимание, что предложенное и принятое решение 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.утиль.Календарь и т. д.
Для сравнения см. другие ответы. Я бы не рекомендовал использовать эти устаревшие классы вообще, потому что полученный код все еще errorprone в некоторых экзотических случаях и/или слишком сложен, учитывая тот факт, что исходный вопрос звучит так просто. В 2015 году у нас действительно лучше библиотеки.
d) О Date4J:
предложенное решение является простым, но иногда будет выполнена в случае високосного года. Просто оценка дня года не является надежной.
e) моя собственная библиотека Time4J:
это работает аналогично Java-8-solution. Просто замените
LocalDatebyPlainDateиChronoUnit.YEARSbyCalendarUnit.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
/** * This Method is unit tested properly for very different cases , * taking care of Leap Year days difference in a year, * and date cases month and Year boundary cases (12/31/1980, 01/01/1980 etc) **/ public static int getAge(Date dateOfBirth) { Calendar today = Calendar.getInstance(); Calendar birthDate = Calendar.getInstance(); int age = 0; birthDate.setTime(dateOfBirth); if (birthDate.after(today)) { throw new IllegalArgumentException("Can't be born in the future"); } age = today.get(Calendar.YEAR) - birthDate.get(Calendar.YEAR); // If birth date is greater than todays date (after 2 days adjustment of leap year) then decrement age one year if ( (birthDate.get(Calendar.DAY_OF_YEAR) - today.get(Calendar.DAY_OF_YEAR) > 3) || (birthDate.get(Calendar.MONTH) > today.get(Calendar.MONTH ))){ age--; // If birth date and todays date are of same month and birth day of month is greater than todays day of month then decrement age }else if ((birthDate.get(Calendar.MONTH) == today.get(Calendar.MONTH )) && (birthDate.get(Calendar.DAY_OF_MONTH) > today.get(Calendar.DAY_OF_MONTH ))){ age--; } return age; }
Если вы используете GWT, вы будете ограничены использованием java.утиль.Дата, вот метод, который принимает дату как целые числа, но все еще использует java.утиль.Дата:
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; }
Я просто использую миллисекунды в год постоянное значение в мою пользу:
Date now = new Date(); long timeBetween = now.getTime() - age.getTime(); double yearsBetween = timeBetween / 3.15576e+10; int age = (int) Math.floor(yearsBetween);
С date4j библиотека :
int age = today.getYear() - birthdate.getYear(); if(today.getDayOfYear() < birthdate.getDayOfYear()){ age = age - 1; }
правильный ответ с помощью JodaTime - это:
public int getAge() { Years years = Years.yearsBetween(new LocalDate(getBirthDate()), new LocalDate()); return years.getYears(); }вы можете даже сократить его в одну строку, если хотите. Я скопировал идею из ответ Бриананью, но я считаю, что это более правильно, как вы видите из комментариев там (и это точно отвечает на вопрос).
попробуйте скопировать это в свой код, затем использовать метод, чтобы получить возраст.
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; }
поля рождение и эффект являются полями даты:
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);это в основном модификация решения Джона О без использования амортизированных методов. Я потратил довольно много времени, пытаясь заставить его код работать в моем коде. Может быть, это спасет других в то время.
Это улучшенная версия выше... учитывая, что вы хотите, чтобы возраст был "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; }
Я использую этот кусок кода для расчета возраста, надеюсь, что это поможет ..нет библиотек, используемых
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 ; }
Как насчет этого?
public Integer calculateAge(Date date) { if (date == null) { return null; } Calendar cal1 = Calendar.getInstance(); cal1.setTime(date); Calendar cal2 = Calendar.getInstance(); int i = 0; while (cal1.before(cal2)) { cal1.add(Calendar.YEAR, 1); i += 1; } return i; }
Stringdateofbirthимеет дату рождения. и формат-это все, что угодно (определено в следующей строке):org.joda.time.format.DateTimeFormatter formatter = org.joda.time.format.DateTimeFormat.forPattern("mm/dd/yyyy");вот как формата:
org.joda.time.DateTime birthdateDate = formatter.parseDateTime(dateofbirth ); org.joda.time.DateMidnight birthdate = new org.joda.time.DateMidnight(birthdateDate.getYear(), birthdateDate.getMonthOfYear(), birthdateDate.getDayOfMonth() ); org.joda.time.DateTime now = new org.joda.time.DateTime(); org.joda.time.Years age = org.joda.time.Years.yearsBetween(birthdate, now); java.lang.String ageStr = java.lang.String.valueOf (age.getYears());переменная
ageStrбудет лет.
элегантных казалось бы, правильно, разность временных меток на основе варианта решения Ярона Ронена.
Я в том числе unit-тест, чтобы доказать, когда и почему это не правильно. Это невозможно из-за (возможно) различного количества високосных дней (и секунд) в любой разнице временных меток. Расхождение должно быть max +-1 день (и одна секунда) для этого алгоритма, см. test2 (), тогда как решение Yaron Ronen основано на полностью постоянном предположении
timeDiff / MILLI_SECONDS_YEARcan отличаются 10 дней для 40-летнего, тем не менее этот вариант тоже неверен.Это сложно, потому что это улучшенный вариант, используя формулу
diffAsCalendar.get(Calendar.YEAR) - 1970, возвращает правильные результаты в большинстве случаев, а число високосных лет в среднем же между двумя датами./** * Compute person's age based on timestamp difference between birth date and given date * and prove it is INCORRECT approach. */ public class AgeUsingTimestamps { public int getAge(Date today, Date dateOfBirth) { long diffAsLong = today.getTime() - dateOfBirth.getTime(); Calendar diffAsCalendar = Calendar.getInstance(); diffAsCalendar.setTimeInMillis(diffAsLong); return diffAsCalendar.get(Calendar.YEAR) - 1970; // base time where timestamp=0, precisely 1/1/1970 00:00:00 } final static DateFormat df = new SimpleDateFormat("dd.MM.yyy HH:mm:ss"); @Test public void test1() throws Exception { Date dateOfBirth = df.parse("10.1.2000 00:00:00"); assertEquals(87, getAge(df.parse("08.1.2088 23:59:59"), dateOfBirth)); assertEquals(87, getAge(df.parse("09.1.2088 23:59:59"), dateOfBirth)); assertEquals(88, getAge(df.parse("10.1.2088 00:00:01"), dateOfBirth)); } @Test public void test2() throws Exception { // between 2000 and 2021 was 6 leap days // but between 1970 (base time) and 1991 there was only 5 leap days // therefore age is switched one day earlier // See http://www.onlineconversion.com/leapyear.htm Date dateOfBirth = df.parse("10.1.2000 00:00:00"); assertEquals(20, getAge(df.parse("08.1.2021 23:59:59"), dateOfBirth)); assertEquals(20, getAge(df.parse("09.1.2021 23:59:59"), dateOfBirth)); // ERROR! returns incorrect age=21 here assertEquals(21, getAge(df.parse("10.1.2021 00:00:01"), dateOfBirth)); } }
public class CalculateAge { private int age; private void setAge(int age){ this.age=age; } public void calculateAge(Date date){ Calendar calendar=Calendar.getInstance(); Calendar calendarnow=Calendar.getInstance(); calendarnow.getTimeZone(); calendar.setTime(date); int getmonth= calendar.get(calendar.MONTH); int getyears= calendar.get(calendar.YEAR); int currentmonth= calendarnow.get(calendarnow.MONTH); int currentyear= calendarnow.get(calendarnow.YEAR); int age = ((currentyear*12+currentmonth)-(getyears*12+getmonth))/12; setAge(age); } public int getAge(){ return this.age; }
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; }
Я ценю все правильные ответы, но это Котлин ответ на тот же вопрос
Я надеюсь, что будет полезно для разработчиков Котлин
fun calculateAge(birthDate: Date): Int { val now = Date() val timeBetween = now.getTime() - birthDate.getTime(); val yearsBetween = timeBetween / 3.15576e+10; return Math.floor(yearsBetween).toInt() }
/** * Compute from string date in the format of yyyy-MM-dd HH:mm:ss the age of a person. * @author Yaron Ronen * @date 04/06/2012 */ private int computeAge(String sDate) { // Initial variables. Date dbDate = null; SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // Parse sDate. try { dbDate = (Date)dateFormat.parse(sDate); } catch(ParseException e) { Log.e("MyApplication","Can not compute age from date:"+sDate,e); return ILLEGAL_DATE; // Const = -2 } // Compute age. long timeDiff = System.currentTimeMillis() - dbDate.getTime(); int age = (int)(timeDiff / MILLI_SECONDS_YEAR); // MILLI_SECONDS_YEAR = 31558464000L; return age; }
вот код java для расчета возраста в год, месяц и дни.
public static AgeModel calculateAge(long birthDate) { int years = 0; int months = 0; int days = 0; if (birthDate != 0) { //create calendar object for birth day Calendar birthDay = Calendar.getInstance(); birthDay.setTimeInMillis(birthDate); //create calendar object for current day Calendar now = Calendar.getInstance(); Calendar current = Calendar.getInstance(); //Get difference between years years = now.get(Calendar.YEAR) - birthDay.get(Calendar.YEAR); //get months int currMonth = now.get(Calendar.MONTH) + 1; int birthMonth = birthDay.get(Calendar.MONTH) + 1; //Get difference between months months = currMonth - birthMonth; //if month difference is in negative then reduce years by one and calculate the number of months. if (months < 0) { years--; months = 12 - birthMonth + currMonth; } else if (months == 0 && now.get(Calendar.DATE) < birthDay.get(Calendar.DATE)) { years--; months = 11; } //Calculate the days if (now.get(Calendar.DATE) > birthDay.get(Calendar.DATE)) days = now.get(Calendar.DATE) - birthDay.get(Calendar.DATE); else if (now.get(Calendar.DATE) < birthDay.get(Calendar.DATE)) { int today = now.get(Calendar.DAY_OF_MONTH); now.add(Calendar.MONTH, -1); days = now.getActualMaximum(Calendar.DAY_OF_MONTH) - birthDay.get(Calendar.DAY_OF_MONTH) + today; } else { days = 0; if (months == 12) { years++; months = 0; } } } //Create new Age object return new AgeModel(days, months, years); }
самый простой способ без каких-либо библиотек:
long today = new Date().getTime(); long diff = today - birth; long age = diff / DateUtils.YEAR_IN_MILLIS;
С Java 8, мы можем вычислить возраст человека с помощью одной строки кода:
public int calCAge(int year, int month,int days){ return LocalDate.now().minus(Period.of(year, month, days)).getYear(); }
public int getAge(Date dateOfBirth) { Calendar now = Calendar.getInstance(); Calendar dob = Calendar.getInstance(); dob.setTime(dateOfBirth); if (dob.after(now)) { throw new IllegalArgumentException("Can't be born in the future"); } int age = now.get(Calendar.YEAR) - dob.get(Calendar.YEAR); if (now.get(Calendar.DAY_OF_YEAR) < dob.get(Calendar.DAY_OF_YEAR)) { age--; } return age; }
import java.io.*; class AgeCalculator { public static void main(String args[]) { InputStreamReader ins=new InputStreamReader(System.in); BufferedReader hey=new BufferedReader(ins); try { System.out.println("Please enter your name: "); String name=hey.readLine(); System.out.println("Please enter your birth date: "); String date=hey.readLine(); System.out.println("please enter your birth month:"); String month=hey.readLine(); System.out.println("please enter your birth year:"); String year=hey.readLine(); System.out.println("please enter current year:"); String cYear=hey.readLine(); int bDate = Integer.parseInt(date); int bMonth = Integer.parseInt(month); int bYear = Integer.parseInt(year); int ccYear=Integer.parseInt(cYear); int age; age = ccYear-bYear; int totalMonth=12; int yourMonth=totalMonth-bMonth; System.out.println(" Hi " + name + " your are " + age + " years " + yourMonth + " months old "); } catch(IOException err) { System.out.println(""); } } }
public int getAge(String birthdate, String today){ // birthdate = "1986-02-22" // today = "2014-09-16" // String class has a split method for splitting a string // split(<delimiter>) // birth[0] = 1986 as string // birth[1] = 02 as string // birth[2] = 22 as string // now[0] = 2014 as string // now[1] = 09 as string // now[2] = 16 as string // **birth** and **now** arrays are automatically contains 3 elements // split method here returns 3 elements because of yyyy-MM-dd value String birth[] = birthdate.split("-"); String now[] = today.split("-"); int age = 0; // let us convert string values into integer values // with the use of Integer.parseInt(<string>) int ybirth = Integer.parseInt(birth[0]); int mbirth = Integer.parseInt(birth[1]); int dbirth = Integer.parseInt(birth[2]); int ynow = Integer.parseInt(now[0]); int mnow = Integer.parseInt(now[1]); int dnow = Integer.parseInt(now[2]); if(ybirth < ynow){ // has age if birth year is lesser than current year age = ynow - ybirth; // let us get the interval of birth year and current year if(mbirth == mnow){ // when birth month comes, it's ok to have age = ynow - ybirth if if(dbirth > dnow) // birth day is coming. need to subtract 1 from age. not yet a bday age--; }else if(mbirth > mnow){ age--; } // birth month is comming. need to subtract 1 from age } return age; }
import java.time.LocalDate; import java.time.ZoneId; import java.time.Period; public class AgeCalculator1 { public static void main(String args[]) { LocalDate start = LocalDate.of(1970, 2, 23); LocalDate end = LocalDate.now(ZoneId.systemDefault()); Period p = Period.between(start, end); //The output of the program is : //45 years 6 months and 6 days. System.out.print(p.getYears() + " year" + (p.getYears() > 1 ? "s " : " ") ); System.out.print(p.getMonths() + " month" + (p.getMonths() > 1 ? "s and " : " and ") ); System.out.print(p.getDays() + " day" + (p.getDays() > 1 ? "s.\n" : ".\n") ); }//method main ends here. }
public int getAge(Date birthDate) { Calendar a = Calendar.getInstance(Locale.US); a.setTime(date); Calendar b = Calendar.getInstance(Locale.US); int age = b.get(YEAR) - a.get(YEAR); if (a.get(MONTH) > b.get(MONTH) || (a.get(MONTH) == b.get(MONTH) && a.get(DATE) > b.get(DATE))) { age--; } return age; }
Comments